diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/core.html b/core.html new file mode 100644 index 00000000..edaf5e38 --- /dev/null +++ b/core.html @@ -0,0 +1,811 @@ +<!DOCTYPE html> +<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head> + +<meta charset="utf-8"> +<meta name="generator" content="quarto-1.3.450"> + +<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes"> + + +<title>hierarchicalforecast - Core </title> +<style> +code{white-space: pre-wrap;} +span.smallcaps{font-variant: small-caps;} +div.columns{display: flex; gap: min(4vw, 1.5em);} +div.column{flex: auto; overflow-x: auto;} +div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;} +ul.task-list{list-style: none;} +ul.task-list li input[type="checkbox"] { + width: 0.8em; + margin: 0 0.8em 0.2em -1em; /* quarto-specific, see https://github.com/quarto-dev/quarto-cli/issues/4556 */ + vertical-align: middle; +} +/* CSS for syntax highlighting */ +pre > code.sourceCode { white-space: pre; position: relative; } +pre > code.sourceCode > span { display: inline-block; line-height: 1.25; } +pre > code.sourceCode > span:empty { height: 1.2em; } +.sourceCode { overflow: visible; } +code.sourceCode > span { color: inherit; text-decoration: inherit; } +div.sourceCode { margin: 1em 0; } +pre.sourceCode { margin: 0; } +@media screen { +div.sourceCode { overflow: auto; } +} +@media print { +pre > code.sourceCode { white-space: pre-wrap; } +pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; } +} +pre.numberSource code + { counter-reset: source-line 0; } +pre.numberSource code > span + { position: relative; left: -4em; counter-increment: source-line; } +pre.numberSource code > span > a:first-child::before + { content: counter(source-line); + position: relative; left: -1em; text-align: right; vertical-align: baseline; + border: none; display: inline-block; + -webkit-touch-callout: none; -webkit-user-select: none; + -khtml-user-select: none; -moz-user-select: none; + -ms-user-select: none; user-select: none; + padding: 0 4px; width: 4em; + } +pre.numberSource { margin-left: 3em; padding-left: 4px; } +div.sourceCode + { } +@media screen { +pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; } +} +</style> + + +<script src="site_libs/quarto-nav/quarto-nav.js"></script> +<script src="site_libs/quarto-nav/headroom.min.js"></script> +<script src="site_libs/clipboard/clipboard.min.js"></script> +<script src="site_libs/quarto-search/autocomplete.umd.js"></script> +<script src="site_libs/quarto-search/fuse.min.js"></script> +<script src="site_libs/quarto-search/quarto-search.js"></script> +<meta name="quarto:offset" content="./"> +<link href="./favicon_png.png" rel="icon" type="image/png"> +<script src="site_libs/quarto-html/quarto.js"></script> +<script src="site_libs/quarto-html/popper.min.js"></script> +<script src="site_libs/quarto-html/tippy.umd.min.js"></script> +<script src="site_libs/quarto-html/anchor.min.js"></script> +<link href="site_libs/quarto-html/tippy.css" rel="stylesheet"> +<link href="site_libs/quarto-html/quarto-syntax-highlighting.css" rel="stylesheet" id="quarto-text-highlighting-styles"> +<script src="site_libs/bootstrap/bootstrap.min.js"></script> +<link href="site_libs/bootstrap/bootstrap-icons.css" rel="stylesheet"> +<link href="site_libs/bootstrap/bootstrap.min.css" rel="stylesheet" id="quarto-bootstrap" data-mode="light"> +<script id="quarto-search-options" type="application/json">{ + "location": "navbar", + "copy-button": false, + "collapse-after": 3, + "panel-placement": "end", + "type": "overlay", + "limit": 20, + "language": { + "search-no-results-text": "No results", + "search-matching-documents-text": "matching documents", + "search-copy-link-title": "Copy link to search", + "search-hide-matches-text": "Hide additional matches", + "search-more-match-text": "more match in this document", + "search-more-matches-text": "more matches in this document", + "search-clear-button-title": "Clear", + "search-detached-cancel-button-title": "Cancel", + "search-submit-button-title": "Submit", + "search-label": "Search" + } +}</script> +<script async="" src="https://www.googletagmanager.com/gtag/js?id=G-NXJNCVR18L"></script> + +<script type="text/javascript"> + +window.dataLayer = window.dataLayer || []; +function gtag(){dataLayer.push(arguments);} +gtag('js', new Date()); +gtag('config', 'G-NXJNCVR18L', { 'anonymize_ip': true}); +</script> + + <script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script> + <script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml-full.js" type="text/javascript"></script> + +<link rel="stylesheet" href="styles.css"> +<meta property="og:title" content="hierarchicalforecast - Core "> +<meta property="og:description" content=""> +<meta property="og:site-name" content="hierarchicalforecast"> +<meta name="twitter:title" content="hierarchicalforecast - Core "> +<meta name="twitter:description" content=""> +<meta name="twitter:card" content="summary"> +</head> + +<body class="nav-sidebar floating nav-fixed"> + +<div id="quarto-search-results"></div> + <header id="quarto-header" class="headroom fixed-top"> + <nav class="navbar navbar-expand-lg navbar-dark "> + <div class="navbar-container container-fluid"> + <div class="navbar-brand-container"> + <a class="navbar-brand" href="./index.html"> + <span class="navbar-title">hierarchicalforecast</span> + </a> + </div> + <div id="quarto-search" class="" title="Search"></div> + <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + <span class="navbar-toggler-icon"></span> +</button> + <div class="collapse navbar-collapse" id="navbarCollapse"> + <ul class="navbar-nav navbar-nav-scroll me-auto"> + <li class="nav-item"> + <a class="nav-link active" href="./examples/tourismsmall.html" rel="" target="" aria-current="page"> + <span class="menu-text">Get Started</span></a> + </li> + <li class="nav-item dropdown "> + <a class="nav-link dropdown-toggle" href="#" id="nav-menu-nixtlaverse" role="button" data-bs-toggle="dropdown" aria-expanded="false" rel="" target=""> + <span class="menu-text">NixtlaVerse</span> + </a> + <ul class="dropdown-menu" aria-labelledby="nav-menu-nixtlaverse"> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/mlforecast" rel="" target=""> + <span class="dropdown-text">MLForecast š¤</span></a> + </li> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/neuralforecast" rel="" target=""> + <span class="dropdown-text">NeuralForecast š§ </span></a> + </li> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/statsforecast" rel="" target=""> + <span class="dropdown-text">StatsForecast ā”ļø</span></a> + </li> + </ul> + </li> + <li class="nav-item dropdown "> + <a class="nav-link dropdown-toggle" href="#" id="nav-menu-help" role="button" data-bs-toggle="dropdown" aria-expanded="false" rel="" target=""> + <span class="menu-text">Help</span> + </a> + <ul class="dropdown-menu" aria-labelledby="nav-menu-help"> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/hierarchicalforecast/issues/new/choose" rel="" target=""><i class="bi bi-bug" role="img"> +</i> + <span class="dropdown-text">Report an Issue</span></a> + </li> + <li> + <a class="dropdown-item" href="https://join.slack.com/t/nixtlacommunity/shared_invite/zt-1kd5m5db7-7OOfy0xVNf1PcvCiAPWvPw" rel="" target=""><i class="bi bi-chat-right-text" role="img"> +</i> + <span class="dropdown-text">Join our Slack</span></a> + </li> + </ul> + </li> +</ul> + <ul class="navbar-nav navbar-nav-scroll ms-auto"> + <li class="nav-item compact"> + <a class="nav-link" href="https://github.com/nixtla/hierarchicalforecast" rel="" target=""><i class="bi bi-github" role="img"> +</i> + <span class="menu-text"></span></a> + </li> + <li class="nav-item compact"> + <a class="nav-link" href="https://twitter.com/nixtlainc" rel="" target=""><i class="bi bi-twitter" role="img" aria-label="Nixtla Twitter"> +</i> + <span class="menu-text"></span></a> + </li> +</ul> + <div class="quarto-navbar-tools"> +</div> + </div> <!-- /navcollapse --> + </div> <!-- /container-fluid --> + </nav> + <nav class="quarto-secondary-nav"> + <div class="container-fluid d-flex"> + <button type="button" class="quarto-btn-toggle btn" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + <i class="bi bi-layout-text-sidebar-reverse"></i> + </button> + <nav class="quarto-page-breadcrumbs" aria-label="breadcrumb"><ol class="breadcrumb"><li class="breadcrumb-item"><a href="./core.html">API Reference</a></li><li class="breadcrumb-item"><a href="./core.html"><span style="color:DarkOrange"> Core </span></a></li></ol></nav> + <a class="flex-grow-1" role="button" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + </a> + </div> + </nav> +</header> +<!-- content --> +<div id="quarto-content" class="quarto-container page-columns page-rows-contents page-layout-article page-navbar"> +<!-- sidebar --> + <nav id="quarto-sidebar" class="sidebar collapse collapse-horizontal sidebar-navigation floating overflow-auto"> + <div class="sidebar-menu-container"> + <ul class="list-unstyled mt-1"> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./index.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Hierarchical Forecast š</span></a> + </div> +</li> + <li class="px-0"><hr class="sidebar-divider hi "></li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-1" aria-expanded="false"> + <span class="menu-text">Getting Started</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-1" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-1" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/installation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Install</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/tourismsmall.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Reconciliation Quick Start</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/introduction.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Introduction</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-2" aria-expanded="false"> + <span class="menu-text">Tutorials</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-2" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-2" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-3" aria-expanded="false"> + <span class="menu-text">Point Reconciliation</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-3" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-3" class="collapse list-unstyled sidebar-section depth2 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/australiandomestictourism.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Geographical Aggregation (Tourism)</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/australianprisonpopulation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Geographical Aggregation (Prison Population)</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/nonnegativereconciliation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Non-Negative MinTrace</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-4" aria-expanded="false"> + <span class="menu-text">Probabilistic Reconciliation</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-4" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-4" class="collapse list-unstyled sidebar-section depth2 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/australiandomestictourism-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Normality</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/australiandomestictourism-bootstraped-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Bootstrap</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/australiandomestictourism-permbu-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">PERMBU</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/tourismlarge-evaluation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Probabilistic Forecast Evaluation</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-5" aria-expanded="false"> + <span class="menu-text">ML Forecast Reconciliation</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-5" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-5" class="collapse list-unstyled sidebar-section depth2 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/hierarchicalforecast-gluonts.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">GluonTS</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/mlframeworksexample.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Neural/MLForecast</span></a> + </div> +</li> + </ul> + </li> + </ul> + </li> + <li class="sidebar-item"> + <span class="menu-text">Methods</span> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-6" aria-expanded="true"> + <span class="menu-text">API Reference</span></a> + <a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-6" aria-expanded="true" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-6" class="collapse list-unstyled sidebar-section depth1 show"> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./core.html" class="sidebar-item-text sidebar-link active"> + <span class="menu-text"><span style="color:DarkOrange"> Core </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./methods.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Reconciliation Methods </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./probabilistic_methods.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Probabilistic Methods </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./evaluation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Hierarchical Evaluation</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./utils.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Aggregation/Visualization Utils</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-7" aria-expanded="false"> + <span class="menu-text">Community</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-7" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-7" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item"> + <span class="menu-text">Contributing</span> + </li> + </ul> + </li> + </ul> + </div> +</nav> +<div id="quarto-sidebar-glass" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass"></div> +<!-- margin-sidebar --> + <div id="quarto-margin-sidebar" class="sidebar margin-sidebar"> + <nav id="TOC" role="doc-toc" class="toc-active"> + <h2 id="toc-title">On this page</h2> + + <ul> + <li><a href="#core.hierarchicalreconciliation" id="toc-core.hierarchicalreconciliation" class="nav-link active" data-scroll-target="#core.hierarchicalreconciliation"><span style="color:DarkBlue"> core.HierarchicalReconciliation </span></a> + <ul class="collapse"> + <li><a href="#init" id="toc-init" class="nav-link" data-scroll-target="#init">init</a></li> + <li><a href="#hierarchicalreconciliation" id="toc-hierarchicalreconciliation" class="nav-link" data-scroll-target="#hierarchicalreconciliation">HierarchicalReconciliation</a></li> + <li><a href="#reconcile" id="toc-reconcile" class="nav-link" data-scroll-target="#reconcile">reconcile</a></li> + <li><a href="#bootstrap_reconcile" id="toc-bootstrap_reconcile" class="nav-link" data-scroll-target="#bootstrap_reconcile">bootstrap_reconcile</a></li> + </ul></li> + <li><a href="#example" id="toc-example" class="nav-link" data-scroll-target="#example"><span style="color:DarkBlue"> Example </span></a></li> + </ul> +<div class="toc-actions"><div><i class="bi bi-github"></i></div><div class="action-links"><p><a href="https://github.com/Nixtla/hierarchicalforecast/issues/new" class="toc-action">Report an issue</a></p></div></div></nav> + </div> +<!-- main --> +<main class="content" id="quarto-document-content"> + +<header id="title-block-header" class="quarto-title-block default"> +<div class="quarto-title"> +<h1 class="title"><span style="color:DarkOrange"> Core </span></h1> +</div> + + + +<div class="quarto-title-meta"> + + + + + </div> + + +</header> + +<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! --> +<p>HierarchicalForecast contains pure Python implementations of hierarchical reconciliation methods as well as a <code>core.HierarchicalReconciliation</code> wrapper class that enables easy interaction with these methods through pandas DataFrames containing the hierarchical time series and the base predictions.</p> +<p>The <code>core.HierarchicalReconciliation</code> reconciliation class operates with the hierarchical time series pd.DataFrame <code>Y_df</code>, the base predictions pd.DataFrame <code>Y_hat_df</code>, the aggregation constraints matrix <code>S</code>. For more information on the creation of aggregation constraints matrix see the utils <a href="https://nixtla.github.io/hierarchicalforecast/utils.html#aggregate">aggregation method</a>.<br><br></p> +<section id="core.hierarchicalreconciliation" class="level1"> +<h1><span style="color:DarkBlue"> core.HierarchicalReconciliation </span></h1> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/core.py#L77" target="_blank" style="float:right; font-size:smaller">source</a></p> +<section id="init" class="level3"> +<h3 class="anchored" data-anchor-id="init">init</h3> +<blockquote class="blockquote"> +<pre><code> init (reconcilers:List[Callable])</code></pre> +</blockquote> +<p>Hierarchical Reconciliation Class.</p> +<p>The <code>core.HierarchicalReconciliation</code> class allows you to efficiently fit multiple HierarchicaForecast methods for a collection of time series and base predictions stored in pandas DataFrames. The <code>Y_df</code> dataframe identifies series and datestamps with the unique_id and ds columns while the y column denotes the target time series variable. The <code>Y_h</code> dataframe stores the base predictions, example (<a href="https://nixtla.github.io/statsforecast/models.html#autoarima">AutoARIMA</a>, <a href="https://nixtla.github.io/statsforecast/models.html#autoets">ETS</a>, etc.).</p> +<p><strong>Parameters:</strong><br> <code>reconcilers</code>: A list of instantiated classes of the <a href="https://nixtla.github.io/hierarchicalforecast/methods.html">reconciliation methods</a> module .<br></p> +<p><strong>References:</strong><br> <a href="https://otexts.com/fpp3/hierarchical.html">Rob J. Hyndman and George Athanasopoulos (2018). āForecasting principles and practice, Hierarchical and Grouped Seriesā.</a></p> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/core.py#L77" target="_blank" style="float:right; font-size:smaller">source</a></p> +</section> +<section id="hierarchicalreconciliation" class="level3"> +<h3 class="anchored" data-anchor-id="hierarchicalreconciliation">HierarchicalReconciliation</h3> +<blockquote class="blockquote"> +<pre><code> HierarchicalReconciliation (reconcilers:List[Callable])</code></pre> +</blockquote> +<p>Hierarchical Reconciliation Class.</p> +<p>The <code>core.HierarchicalReconciliation</code> class allows you to efficiently fit multiple HierarchicaForecast methods for a collection of time series and base predictions stored in pandas DataFrames. The <code>Y_df</code> dataframe identifies series and datestamps with the unique_id and ds columns while the y column denotes the target time series variable. The <code>Y_h</code> dataframe stores the base predictions, example (<a href="https://nixtla.github.io/statsforecast/models.html#autoarima">AutoARIMA</a>, <a href="https://nixtla.github.io/statsforecast/models.html#autoets">ETS</a>, etc.).</p> +<p><strong>Parameters:</strong><br> <code>reconcilers</code>: A list of instantiated classes of the <a href="https://nixtla.github.io/hierarchicalforecast/methods.html">reconciliation methods</a> module .<br></p> +<p><strong>References:</strong><br> <a href="https://otexts.com/fpp3/hierarchical.html">Rob J. Hyndman and George Athanasopoulos (2018). āForecasting principles and practice, Hierarchical and Grouped Seriesā.</a></p> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/core.py#L181" target="_blank" style="float:right; font-size:smaller">source</a></p> +</section> +<section id="reconcile" class="level3"> +<h3 class="anchored" data-anchor-id="reconcile">reconcile</h3> +<blockquote class="blockquote"> +<pre><code> reconcile (Y_hat_df:pandas.core.frame.DataFrame, + S:pandas.core.frame.DataFrame, tags:Dict[str,numpy.ndarray], + Y_df:Optional[pandas.core.frame.DataFrame]=None, + level:Optional[List[int]]=None, + intervals_method:str='normality', num_samples:int=-1, + seed:int=0, sort_df:bool=True, is_balanced:bool=False)</code></pre> +</blockquote> +<p>Hierarchical Reconciliation Method.</p> +<p>The <code>reconcile</code> method is analogous to SKLearn <code>fit_predict</code> method, it applies different reconciliation techniques instantiated in the <code>reconcilers</code> list.</p> +<p>Most reconciliation methods can be described by the following convenient linear algebra notation:</p> +<p><span class="math display">\[\tilde{\mathbf{y}}_{[a,b],\tau} = \mathbf{S}_{[a,b][b]} \mathbf{P}_{[b][a,b]} \hat{\mathbf{y}}_{[a,b],\tau}\]</span></p> +<p>where <span class="math inline">\(a, b\)</span> represent the aggregate and bottom levels, <span class="math inline">\(\mathbf{S}_{[a,b][b]}\)</span> contains the hierarchical aggregation constraints, and <span class="math inline">\(\mathbf{P}_{[b][a,b]}\)</span> varies across reconciliation methods. The reconciled predictions are <span class="math inline">\(\tilde{\mathbf{y}}_{[a,b],\tau}\)</span>, and the base predictions <span class="math inline">\(\hat{\mathbf{y}}_{[a,b],\tau}\)</span>.</p> +<p><strong>Parameters:</strong><br> <code>Y_hat_df</code>: pd.DataFrame, base forecasts with columns <code>ds</code> and models to reconcile indexed by <code>unique_id</code>.<br> <code>Y_df</code>: pd.DataFrame, training set of base time series with columns <code>['ds', 'y']</code> indexed by <code>unique_id</code>.<br> If a class of <code>self.reconciles</code> receives <code>y_hat_insample</code>, <code>Y_df</code> must include them as columns.<br> <code>S</code>: pd.DataFrame with summing matrix of size <code>(base, bottom)</code>, see <a href="https://nixtla.github.io/hierarchicalforecast/utils.html#aggregate">aggregate method</a>.<br> <code>tags</code>: Each key is a level and its value contains tags associated to that level.<br> <code>level</code>: positive float list [0,100), confidence levels for prediction intervals.<br> <code>intervals_method</code>: str, method used to calculate prediction intervals, one of <code>normality</code>, <code>bootstrap</code>, <code>permbu</code>.<br> <code>num_samples</code>: int=-1, if positive return that many probabilistic coherent samples. <code>seed</code>: int=0, random seed for numpy generatorās replicability.<br> <code>sort_df</code> : bool (default=True), if True, sort <code>df</code> by [<code>unique_id</code>,<code>ds</code>].<br> <code>is_balanced</code>: bool=False, wether <code>Y_df</code> is balanced, set it to True to speed things up if <code>Y_df</code> is balanced.<br></p> +<p><strong>Returns:</strong><br> <code>Y_tilde_df</code>: pd.DataFrame, with reconciled predictions.</p> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/core.py#L337" target="_blank" style="float:right; font-size:smaller">source</a></p> +</section> +<section id="bootstrap_reconcile" class="level3"> +<h3 class="anchored" data-anchor-id="bootstrap_reconcile">bootstrap_reconcile</h3> +<blockquote class="blockquote"> +<pre><code> bootstrap_reconcile (Y_hat_df:pandas.core.frame.DataFrame, + S_df:pandas.core.frame.DataFrame, + tags:Dict[str,numpy.ndarray], + Y_df:Optional[pandas.core.frame.DataFrame]=None, + level:Optional[List[int]]=None, + intervals_method:str='normality', + num_samples:int=-1, num_seeds:int=1, + sort_df:bool=True)</code></pre> +</blockquote> +<p>Bootstraped Hierarchical Reconciliation Method.</p> +<p>Applies N times, based on different random seeds, the <code>reconcile</code> method for the different reconciliation techniques instantiated in the <code>reconcilers</code> list.</p> +<p><strong>Parameters:</strong><br> <code>Y_hat_df</code>: pd.DataFrame, base forecasts with columns <code>ds</code> and models to reconcile indexed by <code>unique_id</code>.<br> <code>Y_df</code>: pd.DataFrame, training set of base time series with columns <code>['ds', 'y']</code> indexed by <code>unique_id</code>.<br> If a class of <code>self.reconciles</code> receives <code>y_hat_insample</code>, <code>Y_df</code> must include them as columns.<br> <code>S</code>: pd.DataFrame with summing matrix of size <code>(base, bottom)</code>, see <a href="https://nixtla.github.io/hierarchicalforecast/utils.html#aggregate">aggregate method</a>.<br> <code>tags</code>: Each key is a level and its value contains tags associated to that level.<br> <code>level</code>: positive float list [0,100), confidence levels for prediction intervals.<br> <code>intervals_method</code>: str, method used to calculate prediction intervals, one of <code>normality</code>, <code>bootstrap</code>, <code>permbu</code>.<br> <code>num_samples</code>: int=-1, if positive return that many probabilistic coherent samples. <code>num_seeds</code>: int=1, random seed for numpy generatorās replicability.<br> <code>sort_df</code> : bool (default=True), if True, sort <code>df</code> by [<code>unique_id</code>,<code>ds</code>].<br></p> +<p><strong>Returns:</strong><br> <code>Y_bootstrap_df</code>: pd.DataFrame, with bootstraped reconciled predictions.</p> +</section> +</section> +<section id="example" class="level1"> +<h1><span style="color:DarkBlue"> Example </span></h1> +<div class="cell"> +<div class="sourceCode cell-code" id="cb5"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> numpy <span class="im">as</span> np</span> +<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> pandas <span class="im">as</span> pd</span> +<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> statsforecast.core <span class="im">import</span> StatsForecast</span> +<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> statsforecast.models <span class="im">import</span> ETS, Naive</span> +<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> hierarchicalforecast.utils <span class="im">import</span> aggregate</span> +<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> hierarchicalforecast.core <span class="im">import</span> HierarchicalReconciliation</span> +<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> hierarchicalforecast.methods <span class="im">import</span> BottomUp, MinTrace</span> +<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb5-11"><a href="#cb5-11" aria-hidden="true" tabindex="-1"></a><span class="co"># Load TourismSmall dataset</span></span> +<span id="cb5-12"><a href="#cb5-12" aria-hidden="true" tabindex="-1"></a>df <span class="op">=</span> pd.read_csv(<span class="st">'https://raw.githubusercontent.com/Nixtla/transfer-learning-time-series/main/datasets/tourism.csv'</span>)</span> +<span id="cb5-13"><a href="#cb5-13" aria-hidden="true" tabindex="-1"></a>df <span class="op">=</span> df.rename({<span class="st">'Trips'</span>: <span class="st">'y'</span>, <span class="st">'Quarter'</span>: <span class="st">'ds'</span>}, axis<span class="op">=</span><span class="dv">1</span>)</span> +<span id="cb5-14"><a href="#cb5-14" aria-hidden="true" tabindex="-1"></a>df.insert(<span class="dv">0</span>, <span class="st">'Country'</span>, <span class="st">'Australia'</span>)</span> +<span id="cb5-15"><a href="#cb5-15" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb5-16"><a href="#cb5-16" aria-hidden="true" tabindex="-1"></a><span class="co"># Create hierarchical seires based on geographic levels and purpose</span></span> +<span id="cb5-17"><a href="#cb5-17" aria-hidden="true" tabindex="-1"></a><span class="co"># And Convert quarterly ds string to pd.datetime format</span></span> +<span id="cb5-18"><a href="#cb5-18" aria-hidden="true" tabindex="-1"></a>hierarchy_levels <span class="op">=</span> [[<span class="st">'Country'</span>],</span> +<span id="cb5-19"><a href="#cb5-19" aria-hidden="true" tabindex="-1"></a> [<span class="st">'Country'</span>, <span class="st">'State'</span>], </span> +<span id="cb5-20"><a href="#cb5-20" aria-hidden="true" tabindex="-1"></a> [<span class="st">'Country'</span>, <span class="st">'Purpose'</span>], </span> +<span id="cb5-21"><a href="#cb5-21" aria-hidden="true" tabindex="-1"></a> [<span class="st">'Country'</span>, <span class="st">'State'</span>, <span class="st">'Region'</span>], </span> +<span id="cb5-22"><a href="#cb5-22" aria-hidden="true" tabindex="-1"></a> [<span class="st">'Country'</span>, <span class="st">'State'</span>, <span class="st">'Purpose'</span>], </span> +<span id="cb5-23"><a href="#cb5-23" aria-hidden="true" tabindex="-1"></a> [<span class="st">'Country'</span>, <span class="st">'State'</span>, <span class="st">'Region'</span>, <span class="st">'Purpose'</span>]]</span> +<span id="cb5-24"><a href="#cb5-24" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb5-25"><a href="#cb5-25" aria-hidden="true" tabindex="-1"></a>Y_df, S_df, tags <span class="op">=</span> aggregate(df<span class="op">=</span>df, spec<span class="op">=</span>hierarchy_levels)</span> +<span id="cb5-26"><a href="#cb5-26" aria-hidden="true" tabindex="-1"></a>qs <span class="op">=</span> Y_df[<span class="st">'ds'</span>].<span class="bu">str</span>.replace(<span class="vs">r'(\d+) (Q\d)'</span>, <span class="vs">r'\1-\2'</span>, regex<span class="op">=</span><span class="va">True</span>)</span> +<span id="cb5-27"><a href="#cb5-27" aria-hidden="true" tabindex="-1"></a>Y_df[<span class="st">'ds'</span>] <span class="op">=</span> pd.PeriodIndex(qs, freq<span class="op">=</span><span class="st">'Q'</span>).to_timestamp()</span> +<span id="cb5-28"><a href="#cb5-28" aria-hidden="true" tabindex="-1"></a>Y_df <span class="op">=</span> Y_df.reset_index()</span> +<span id="cb5-29"><a href="#cb5-29" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb5-30"><a href="#cb5-30" aria-hidden="true" tabindex="-1"></a><span class="co"># Split train/test sets</span></span> +<span id="cb5-31"><a href="#cb5-31" aria-hidden="true" tabindex="-1"></a>Y_test_df <span class="op">=</span> Y_df.groupby(<span class="st">'unique_id'</span>).tail(<span class="dv">4</span>)</span> +<span id="cb5-32"><a href="#cb5-32" aria-hidden="true" tabindex="-1"></a>Y_train_df <span class="op">=</span> Y_df.drop(Y_test_df.index)</span> +<span id="cb5-33"><a href="#cb5-33" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb5-34"><a href="#cb5-34" aria-hidden="true" tabindex="-1"></a><span class="co"># Compute base auto-ETS predictions</span></span> +<span id="cb5-35"><a href="#cb5-35" aria-hidden="true" tabindex="-1"></a><span class="co"># Careful identifying correct data freq, this data quarterly 'Q'</span></span> +<span id="cb5-36"><a href="#cb5-36" aria-hidden="true" tabindex="-1"></a>fcst <span class="op">=</span> StatsForecast(df<span class="op">=</span>Y_train_df,</span> +<span id="cb5-37"><a href="#cb5-37" aria-hidden="true" tabindex="-1"></a> <span class="co">#models=[ETS(season_length=12), Naive()],</span></span> +<span id="cb5-38"><a href="#cb5-38" aria-hidden="true" tabindex="-1"></a> models<span class="op">=</span>[Naive()],</span> +<span id="cb5-39"><a href="#cb5-39" aria-hidden="true" tabindex="-1"></a> freq<span class="op">=</span><span class="st">'Q'</span>, n_jobs<span class="op">=-</span><span class="dv">1</span>)</span> +<span id="cb5-40"><a href="#cb5-40" aria-hidden="true" tabindex="-1"></a>Y_hat_df <span class="op">=</span> fcst.forecast(h<span class="op">=</span><span class="dv">4</span>, fitted<span class="op">=</span><span class="va">True</span>)</span> +<span id="cb5-41"><a href="#cb5-41" aria-hidden="true" tabindex="-1"></a>Y_fitted_df <span class="op">=</span> fcst.forecast_fitted_values()</span> +<span id="cb5-42"><a href="#cb5-42" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb5-43"><a href="#cb5-43" aria-hidden="true" tabindex="-1"></a><span class="co"># Reconcile the base predictions</span></span> +<span id="cb5-44"><a href="#cb5-44" aria-hidden="true" tabindex="-1"></a>Y_train_df <span class="op">=</span> Y_train_df.reset_index().set_index(<span class="st">'unique_id'</span>)</span> +<span id="cb5-45"><a href="#cb5-45" aria-hidden="true" tabindex="-1"></a>Y_hat_df <span class="op">=</span> Y_hat_df.reset_index().set_index(<span class="st">'unique_id'</span>)</span> +<span id="cb5-46"><a href="#cb5-46" aria-hidden="true" tabindex="-1"></a>reconcilers <span class="op">=</span> [BottomUp(),</span> +<span id="cb5-47"><a href="#cb5-47" aria-hidden="true" tabindex="-1"></a> MinTrace(method<span class="op">=</span><span class="st">'mint_shrink'</span>)]</span> +<span id="cb5-48"><a href="#cb5-48" aria-hidden="true" tabindex="-1"></a>hrec <span class="op">=</span> HierarchicalReconciliation(reconcilers<span class="op">=</span>reconcilers)</span> +<span id="cb5-49"><a href="#cb5-49" aria-hidden="true" tabindex="-1"></a>Y_rec_df <span class="op">=</span> hrec.reconcile(Y_hat_df<span class="op">=</span>Y_hat_df, </span> +<span id="cb5-50"><a href="#cb5-50" aria-hidden="true" tabindex="-1"></a> Y_df<span class="op">=</span>Y_fitted_df,</span> +<span id="cb5-51"><a href="#cb5-51" aria-hidden="true" tabindex="-1"></a> S<span class="op">=</span>S_df, tags<span class="op">=</span>tags)</span> +<span id="cb5-52"><a href="#cb5-52" aria-hidden="true" tabindex="-1"></a>Y_rec_df.groupby(<span class="st">'unique_id'</span>).head(<span class="dv">2</span>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> + + +</section> + +<p>If you find the code useful, please ā us on <a href="https://github.com/nixtla/hierarchicalforecast">Github</a></p></main> <!-- /main --> +<script id="quarto-html-after-body" type="application/javascript"> +window.document.addEventListener("DOMContentLoaded", function (event) { + const toggleBodyColorMode = (bsSheetEl) => { + const mode = bsSheetEl.getAttribute("data-mode"); + const bodyEl = window.document.querySelector("body"); + if (mode === "dark") { + bodyEl.classList.add("quarto-dark"); + bodyEl.classList.remove("quarto-light"); + } else { + bodyEl.classList.add("quarto-light"); + bodyEl.classList.remove("quarto-dark"); + } + } + const toggleBodyColorPrimary = () => { + const bsSheetEl = window.document.querySelector("link#quarto-bootstrap"); + if (bsSheetEl) { + toggleBodyColorMode(bsSheetEl); + } + } + toggleBodyColorPrimary(); + const icon = "ī§"; + const anchorJS = new window.AnchorJS(); + anchorJS.options = { + placement: 'right', + icon: icon + }; + anchorJS.add('.anchored'); + const isCodeAnnotation = (el) => { + for (const clz of el.classList) { + if (clz.startsWith('code-annotation-')) { + return true; + } + } + return false; + } + const clipboard = new window.ClipboardJS('.code-copy-button', { + text: function(trigger) { + const codeEl = trigger.previousElementSibling.cloneNode(true); + for (const childEl of codeEl.children) { + if (isCodeAnnotation(childEl)) { + childEl.remove(); + } + } + return codeEl.innerText; + } + }); + clipboard.on('success', function(e) { + // button target + const button = e.trigger; + // don't keep focus + button.blur(); + // flash "checked" + button.classList.add('code-copy-button-checked'); + var currentTitle = button.getAttribute("title"); + button.setAttribute("title", "Copied!"); + let tooltip; + if (window.bootstrap) { + button.setAttribute("data-bs-toggle", "tooltip"); + button.setAttribute("data-bs-placement", "left"); + button.setAttribute("data-bs-title", "Copied!"); + tooltip = new bootstrap.Tooltip(button, + { trigger: "manual", + customClass: "code-copy-button-tooltip", + offset: [0, -8]}); + tooltip.show(); + } + setTimeout(function() { + if (tooltip) { + tooltip.hide(); + button.removeAttribute("data-bs-title"); + button.removeAttribute("data-bs-toggle"); + button.removeAttribute("data-bs-placement"); + } + button.setAttribute("title", currentTitle); + button.classList.remove('code-copy-button-checked'); + }, 1000); + // clear code selection + e.clearSelection(); + }); + function tippyHover(el, contentFn) { + const config = { + allowHTML: true, + content: contentFn, + maxWidth: 500, + delay: 100, + arrow: false, + appendTo: function(el) { + return el.parentElement; + }, + interactive: true, + interactiveBorder: 10, + theme: 'quarto', + placement: 'bottom-start' + }; + window.tippy(el, config); + } + const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]'); + for (var i=0; i<noterefs.length; i++) { + const ref = noterefs[i]; + tippyHover(ref, function() { + // use id or data attribute instead here + let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href'); + try { href = new URL(href).hash; } catch {} + const id = href.replace(/^#\/?/, ""); + const note = window.document.getElementById(id); + return note.innerHTML; + }); + } + let selectedAnnoteEl; + const selectorForAnnotation = ( cell, annotation) => { + let cellAttr = 'data-code-cell="' + cell + '"'; + let lineAttr = 'data-code-annotation="' + annotation + '"'; + const selector = 'span[' + cellAttr + '][' + lineAttr + ']'; + return selector; + } + const selectCodeLines = (annoteEl) => { + const doc = window.document; + const targetCell = annoteEl.getAttribute("data-target-cell"); + const targetAnnotation = annoteEl.getAttribute("data-target-annotation"); + const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation)); + const lines = annoteSpan.getAttribute("data-code-lines").split(","); + const lineIds = lines.map((line) => { + return targetCell + "-" + line; + }) + let top = null; + let height = null; + let parent = null; + if (lineIds.length > 0) { + //compute the position of the single el (top and bottom and make a div) + const el = window.document.getElementById(lineIds[0]); + top = el.offsetTop; + height = el.offsetHeight; + parent = el.parentElement.parentElement; + if (lineIds.length > 1) { + const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]); + const bottom = lastEl.offsetTop + lastEl.offsetHeight; + height = bottom - top; + } + if (top !== null && height !== null && parent !== null) { + // cook up a div (if necessary) and position it + let div = window.document.getElementById("code-annotation-line-highlight"); + if (div === null) { + div = window.document.createElement("div"); + div.setAttribute("id", "code-annotation-line-highlight"); + div.style.position = 'absolute'; + parent.appendChild(div); + } + div.style.top = top - 2 + "px"; + div.style.height = height + 4 + "px"; + let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter"); + if (gutterDiv === null) { + gutterDiv = window.document.createElement("div"); + gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter"); + gutterDiv.style.position = 'absolute'; + const codeCell = window.document.getElementById(targetCell); + const gutter = codeCell.querySelector('.code-annotation-gutter'); + gutter.appendChild(gutterDiv); + } + gutterDiv.style.top = top - 2 + "px"; + gutterDiv.style.height = height + 4 + "px"; + } + selectedAnnoteEl = annoteEl; + } + }; + const unselectCodeLines = () => { + const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"]; + elementsIds.forEach((elId) => { + const div = window.document.getElementById(elId); + if (div) { + div.remove(); + } + }); + selectedAnnoteEl = undefined; + }; + // Attach click handler to the DT + const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); + for (const annoteDlNode of annoteDls) { + annoteDlNode.addEventListener('click', (event) => { + const clickedEl = event.target; + if (clickedEl !== selectedAnnoteEl) { + unselectCodeLines(); + const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active'); + if (activeEl) { + activeEl.classList.remove('code-annotation-active'); + } + selectCodeLines(clickedEl); + clickedEl.classList.add('code-annotation-active'); + } else { + // Unselect the line + unselectCodeLines(); + clickedEl.classList.remove('code-annotation-active'); + } + }); + } + const findCites = (el) => { + const parentEl = el.parentElement; + if (parentEl) { + const cites = parentEl.dataset.cites; + if (cites) { + return { + el, + cites: cites.split(' ') + }; + } else { + return findCites(el.parentElement) + } + } else { + return undefined; + } + }; + var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]'); + for (var i=0; i<bibliorefs.length; i++) { + const ref = bibliorefs[i]; + const citeInfo = findCites(ref); + if (citeInfo) { + tippyHover(citeInfo.el, function() { + var popup = window.document.createElement('div'); + citeInfo.cites.forEach(function(cite) { + var citeDiv = window.document.createElement('div'); + citeDiv.classList.add('hanging-indent'); + citeDiv.classList.add('csl-entry'); + var biblioDiv = window.document.getElementById('ref-' + cite); + if (biblioDiv) { + citeDiv.innerHTML = biblioDiv.innerHTML; + } + popup.appendChild(citeDiv); + }); + return popup.innerHTML; + }); + } + } +}); +</script> +</div> <!-- /content --> + + + +</body></html> \ No newline at end of file diff --git a/evaluation.html b/evaluation.html new file mode 100644 index 00000000..907962bc --- /dev/null +++ b/evaluation.html @@ -0,0 +1,862 @@ +<!DOCTYPE html> +<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head> + +<meta charset="utf-8"> +<meta name="generator" content="quarto-1.3.450"> + +<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes"> + + +<title>hierarchicalforecast - Hierarchical Evaluation</title> +<style> +code{white-space: pre-wrap;} +span.smallcaps{font-variant: small-caps;} +div.columns{display: flex; gap: min(4vw, 1.5em);} +div.column{flex: auto; overflow-x: auto;} +div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;} +ul.task-list{list-style: none;} +ul.task-list li input[type="checkbox"] { + width: 0.8em; + margin: 0 0.8em 0.2em -1em; /* quarto-specific, see https://github.com/quarto-dev/quarto-cli/issues/4556 */ + vertical-align: middle; +} +/* CSS for syntax highlighting */ +pre > code.sourceCode { white-space: pre; position: relative; } +pre > code.sourceCode > span { display: inline-block; line-height: 1.25; } +pre > code.sourceCode > span:empty { height: 1.2em; } +.sourceCode { overflow: visible; } +code.sourceCode > span { color: inherit; text-decoration: inherit; } +div.sourceCode { margin: 1em 0; } +pre.sourceCode { margin: 0; } +@media screen { +div.sourceCode { overflow: auto; } +} +@media print { +pre > code.sourceCode { white-space: pre-wrap; } +pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; } +} +pre.numberSource code + { counter-reset: source-line 0; } +pre.numberSource code > span + { position: relative; left: -4em; counter-increment: source-line; } +pre.numberSource code > span > a:first-child::before + { content: counter(source-line); + position: relative; left: -1em; text-align: right; vertical-align: baseline; + border: none; display: inline-block; + -webkit-touch-callout: none; -webkit-user-select: none; + -khtml-user-select: none; -moz-user-select: none; + -ms-user-select: none; user-select: none; + padding: 0 4px; width: 4em; + } +pre.numberSource { margin-left: 3em; padding-left: 4px; } +div.sourceCode + { } +@media screen { +pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; } +} +</style> + + +<script src="site_libs/quarto-nav/quarto-nav.js"></script> +<script src="site_libs/quarto-nav/headroom.min.js"></script> +<script src="site_libs/clipboard/clipboard.min.js"></script> +<script src="site_libs/quarto-search/autocomplete.umd.js"></script> +<script src="site_libs/quarto-search/fuse.min.js"></script> +<script src="site_libs/quarto-search/quarto-search.js"></script> +<meta name="quarto:offset" content="./"> +<link href="./favicon_png.png" rel="icon" type="image/png"> +<script src="site_libs/quarto-html/quarto.js"></script> +<script src="site_libs/quarto-html/popper.min.js"></script> +<script src="site_libs/quarto-html/tippy.umd.min.js"></script> +<script src="site_libs/quarto-html/anchor.min.js"></script> +<link href="site_libs/quarto-html/tippy.css" rel="stylesheet"> +<link href="site_libs/quarto-html/quarto-syntax-highlighting.css" rel="stylesheet" id="quarto-text-highlighting-styles"> +<script src="site_libs/bootstrap/bootstrap.min.js"></script> +<link href="site_libs/bootstrap/bootstrap-icons.css" rel="stylesheet"> +<link href="site_libs/bootstrap/bootstrap.min.css" rel="stylesheet" id="quarto-bootstrap" data-mode="light"> +<script id="quarto-search-options" type="application/json">{ + "location": "navbar", + "copy-button": false, + "collapse-after": 3, + "panel-placement": "end", + "type": "overlay", + "limit": 20, + "language": { + "search-no-results-text": "No results", + "search-matching-documents-text": "matching documents", + "search-copy-link-title": "Copy link to search", + "search-hide-matches-text": "Hide additional matches", + "search-more-match-text": "more match in this document", + "search-more-matches-text": "more matches in this document", + "search-clear-button-title": "Clear", + "search-detached-cancel-button-title": "Cancel", + "search-submit-button-title": "Submit", + "search-label": "Search" + } +}</script> +<script async="" src="https://www.googletagmanager.com/gtag/js?id=G-NXJNCVR18L"></script> + +<script type="text/javascript"> + +window.dataLayer = window.dataLayer || []; +function gtag(){dataLayer.push(arguments);} +gtag('js', new Date()); +gtag('config', 'G-NXJNCVR18L', { 'anonymize_ip': true}); +</script> + + <script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script> + <script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml-full.js" type="text/javascript"></script> + +<link rel="stylesheet" href="styles.css"> +<meta property="og:title" content="hierarchicalforecast - Hierarchical Evaluation"> +<meta property="og:description" content=""> +<meta property="og:site-name" content="hierarchicalforecast"> +<meta name="twitter:title" content="hierarchicalforecast - Hierarchical Evaluation"> +<meta name="twitter:description" content=""> +<meta name="twitter:card" content="summary"> +</head> + +<body class="nav-sidebar floating nav-fixed"> + +<div id="quarto-search-results"></div> + <header id="quarto-header" class="headroom fixed-top"> + <nav class="navbar navbar-expand-lg navbar-dark "> + <div class="navbar-container container-fluid"> + <div class="navbar-brand-container"> + <a class="navbar-brand" href="./index.html"> + <span class="navbar-title">hierarchicalforecast</span> + </a> + </div> + <div id="quarto-search" class="" title="Search"></div> + <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + <span class="navbar-toggler-icon"></span> +</button> + <div class="collapse navbar-collapse" id="navbarCollapse"> + <ul class="navbar-nav navbar-nav-scroll me-auto"> + <li class="nav-item"> + <a class="nav-link active" href="./examples/tourismsmall.html" rel="" target="" aria-current="page"> + <span class="menu-text">Get Started</span></a> + </li> + <li class="nav-item dropdown "> + <a class="nav-link dropdown-toggle" href="#" id="nav-menu-nixtlaverse" role="button" data-bs-toggle="dropdown" aria-expanded="false" rel="" target=""> + <span class="menu-text">NixtlaVerse</span> + </a> + <ul class="dropdown-menu" aria-labelledby="nav-menu-nixtlaverse"> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/mlforecast" rel="" target=""> + <span class="dropdown-text">MLForecast š¤</span></a> + </li> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/neuralforecast" rel="" target=""> + <span class="dropdown-text">NeuralForecast š§ </span></a> + </li> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/statsforecast" rel="" target=""> + <span class="dropdown-text">StatsForecast ā”ļø</span></a> + </li> + </ul> + </li> + <li class="nav-item dropdown "> + <a class="nav-link dropdown-toggle" href="#" id="nav-menu-help" role="button" data-bs-toggle="dropdown" aria-expanded="false" rel="" target=""> + <span class="menu-text">Help</span> + </a> + <ul class="dropdown-menu" aria-labelledby="nav-menu-help"> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/hierarchicalforecast/issues/new/choose" rel="" target=""><i class="bi bi-bug" role="img"> +</i> + <span class="dropdown-text">Report an Issue</span></a> + </li> + <li> + <a class="dropdown-item" href="https://join.slack.com/t/nixtlacommunity/shared_invite/zt-1kd5m5db7-7OOfy0xVNf1PcvCiAPWvPw" rel="" target=""><i class="bi bi-chat-right-text" role="img"> +</i> + <span class="dropdown-text">Join our Slack</span></a> + </li> + </ul> + </li> +</ul> + <ul class="navbar-nav navbar-nav-scroll ms-auto"> + <li class="nav-item compact"> + <a class="nav-link" href="https://github.com/nixtla/hierarchicalforecast" rel="" target=""><i class="bi bi-github" role="img"> +</i> + <span class="menu-text"></span></a> + </li> + <li class="nav-item compact"> + <a class="nav-link" href="https://twitter.com/nixtlainc" rel="" target=""><i class="bi bi-twitter" role="img" aria-label="Nixtla Twitter"> +</i> + <span class="menu-text"></span></a> + </li> +</ul> + <div class="quarto-navbar-tools"> +</div> + </div> <!-- /navcollapse --> + </div> <!-- /container-fluid --> + </nav> + <nav class="quarto-secondary-nav"> + <div class="container-fluid d-flex"> + <button type="button" class="quarto-btn-toggle btn" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + <i class="bi bi-layout-text-sidebar-reverse"></i> + </button> + <nav class="quarto-page-breadcrumbs" aria-label="breadcrumb"><ol class="breadcrumb"><li class="breadcrumb-item"><a href="./core.html">API Reference</a></li><li class="breadcrumb-item"><a href="./evaluation.html">Hierarchical Evaluation</a></li></ol></nav> + <a class="flex-grow-1" role="button" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + </a> + </div> + </nav> +</header> +<!-- content --> +<div id="quarto-content" class="quarto-container page-columns page-rows-contents page-layout-article page-navbar"> +<!-- sidebar --> + <nav id="quarto-sidebar" class="sidebar collapse collapse-horizontal sidebar-navigation floating overflow-auto"> + <div class="sidebar-menu-container"> + <ul class="list-unstyled mt-1"> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./index.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Hierarchical Forecast š</span></a> + </div> +</li> + <li class="px-0"><hr class="sidebar-divider hi "></li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-1" aria-expanded="false"> + <span class="menu-text">Getting Started</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-1" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-1" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/installation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Install</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/tourismsmall.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Reconciliation Quick Start</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/introduction.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Introduction</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-2" aria-expanded="false"> + <span class="menu-text">Tutorials</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-2" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-2" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-3" aria-expanded="false"> + <span class="menu-text">Point Reconciliation</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-3" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-3" class="collapse list-unstyled sidebar-section depth2 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/australiandomestictourism.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Geographical Aggregation (Tourism)</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/australianprisonpopulation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Geographical Aggregation (Prison Population)</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/nonnegativereconciliation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Non-Negative MinTrace</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-4" aria-expanded="false"> + <span class="menu-text">Probabilistic Reconciliation</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-4" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-4" class="collapse list-unstyled sidebar-section depth2 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/australiandomestictourism-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Normality</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/australiandomestictourism-bootstraped-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Bootstrap</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/australiandomestictourism-permbu-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">PERMBU</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/tourismlarge-evaluation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Probabilistic Forecast Evaluation</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-5" aria-expanded="false"> + <span class="menu-text">ML Forecast Reconciliation</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-5" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-5" class="collapse list-unstyled sidebar-section depth2 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/hierarchicalforecast-gluonts.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">GluonTS</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/mlframeworksexample.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Neural/MLForecast</span></a> + </div> +</li> + </ul> + </li> + </ul> + </li> + <li class="sidebar-item"> + <span class="menu-text">Methods</span> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-6" aria-expanded="true"> + <span class="menu-text">API Reference</span></a> + <a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-6" aria-expanded="true" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-6" class="collapse list-unstyled sidebar-section depth1 show"> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./core.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Core </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./methods.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Reconciliation Methods </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./probabilistic_methods.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Probabilistic Methods </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./evaluation.html" class="sidebar-item-text sidebar-link active"> + <span class="menu-text">Hierarchical Evaluation</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./utils.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Aggregation/Visualization Utils</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-7" aria-expanded="false"> + <span class="menu-text">Community</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-7" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-7" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item"> + <span class="menu-text">Contributing</span> + </li> + </ul> + </li> + </ul> + </div> +</nav> +<div id="quarto-sidebar-glass" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass"></div> +<!-- margin-sidebar --> + <div id="quarto-margin-sidebar" class="sidebar margin-sidebar"> + <nav id="TOC" role="doc-toc" class="toc-active"> + <h2 id="toc-title">On this page</h2> + + <ul> + <li><a href="#accuracy-measurements" id="toc-accuracy-measurements" class="nav-link active" data-scroll-target="#accuracy-measurements"><span style="color:DarkBlue"> Accuracy Measurements </span></a> + <ul class="collapse"> + <li><a href="#relative-mean-squared-error" id="toc-relative-mean-squared-error" class="nav-link" data-scroll-target="#relative-mean-squared-error">Relative Mean Squared Error</a> + <ul class="collapse"> + <li><a href="#rel_mse" id="toc-rel_mse" class="nav-link" data-scroll-target="#rel_mse">rel_mse</a></li> + </ul></li> + <li><a href="#mean-squared-scaled-error" id="toc-mean-squared-scaled-error" class="nav-link" data-scroll-target="#mean-squared-scaled-error">Mean Squared Scaled Error</a> + <ul class="collapse"> + <li><a href="#msse" id="toc-msse" class="nav-link" data-scroll-target="#msse">msse</a></li> + </ul></li> + <li><a href="#scaled-crps" id="toc-scaled-crps" class="nav-link" data-scroll-target="#scaled-crps">Scaled CRPS</a> + <ul class="collapse"> + <li><a href="#scaled_crps" id="toc-scaled_crps" class="nav-link" data-scroll-target="#scaled_crps">scaled_crps</a></li> + </ul></li> + <li><a href="#energy-score" id="toc-energy-score" class="nav-link" data-scroll-target="#energy-score">Energy Score</a> + <ul class="collapse"> + <li><a href="#energy_score" id="toc-energy_score" class="nav-link" data-scroll-target="#energy_score">energy_score</a></li> + <li><a href="#log_score" id="toc-log_score" class="nav-link" data-scroll-target="#log_score">log_score</a></li> + </ul></li> + </ul></li> + <li><a href="#hierarchical-evaluation" id="toc-hierarchical-evaluation" class="nav-link" data-scroll-target="#hierarchical-evaluation"><span style="color:DarkBlue"> Hierarchical Evaluation </span></a> + <ul class="collapse"> + <li><a href="#hierarchicalevaluation" id="toc-hierarchicalevaluation" class="nav-link" data-scroll-target="#hierarchicalevaluation">HierarchicalEvaluation</a></li> + <li><a href="#hierarchicalevaluation.evaluate" id="toc-hierarchicalevaluation.evaluate" class="nav-link" data-scroll-target="#hierarchicalevaluation.evaluate">HierarchicalEvaluation.evaluate</a></li> + </ul></li> + <li><a href="#example" id="toc-example" class="nav-link" data-scroll-target="#example"><span style="color:DarkBlue"> Example </span></a></li> + <li><a href="#references" id="toc-references" class="nav-link" data-scroll-target="#references"><span style="color:DarkBlue"> References </span></a></li> + </ul> +<div class="toc-actions"><div><i class="bi bi-github"></i></div><div class="action-links"><p><a href="https://github.com/Nixtla/hierarchicalforecast/issues/new" class="toc-action">Report an issue</a></p></div></div></nav> + </div> +<!-- main --> +<main class="content" id="quarto-document-content"> + +<header id="title-block-header" class="quarto-title-block default"> +<div class="quarto-title"> +<h1 class="title">Hierarchical Evaluation</h1> +</div> + + + +<div class="quarto-title-meta"> + + + + + </div> + + +</header> + +<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! --> +<p>To assist the evaluation of hierarchical forecasting systems, we make available accuracy metrics along with the <a href="https://Nixtla.github.io/hierarchicalforecast/evaluation.html#hierarchicalevaluation"><code>HierarchicalEvaluation</code></a> module that facilitates the measurement of predictionās accuracy through the hierarchy levels.</p> +<p>The available metrics include point and probabilistic multivariate scoring rules that were used in previous hierarchical forecasting studies.</p> +<section id="accuracy-measurements" class="level1"> +<h1><span style="color:DarkBlue"> Accuracy Measurements </span></h1> +<section id="relative-mean-squared-error" class="level2"> +<h2 class="anchored" data-anchor-id="relative-mean-squared-error">Relative Mean Squared Error</h2> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/evaluation.py#L111" target="_blank" style="float:right; font-size:smaller">source</a></p> +<section id="rel_mse" class="level3"> +<h3 class="anchored" data-anchor-id="rel_mse">rel_mse</h3> +<blockquote class="blockquote"> +<pre><code> rel_mse (y, y_hat, y_train, mask=None)</code></pre> +</blockquote> +<p>Relative Mean Squared Error</p> +<p>Computes Relative mean squared error (RelMSE), as proposed by Hyndman & Koehler (2006) as an alternative to percentage errors, to avoid measure unstability.</p> +<p><span class="math display">\[ \mathrm{RelMSE}(\mathbf{y}, \mathbf{\hat{y}}, \mathbf{\hat{y}}^{naive1}) = +\frac{\mathrm{MSE}(\mathbf{y}, \mathbf{\hat{y}})}{\mathrm{MSE}(\mathbf{y}, \mathbf{\hat{y}}^{naive1})} \]</span></p> +<p><strong>Parameters:</strong><br> <code>y</code>: numpy array, Actual values of size (<code>n_series</code>, <code>horizon</code>).<br> <code>y_hat</code>: numpy array, Predicted values (<code>n_series</code>, <code>horizon</code>).<br> <code>mask</code>: numpy array, Specifies date stamps per serie to consider in loss.<br></p> +<p><strong>Returns:</strong><br> <code>loss</code>: float.</p> +<p><strong>References:</strong><br> - <a href="https://www.sciencedirect.com/science/article/pii/S0169207006000239">Hyndman, R. J and Koehler, A. B. (2006). āAnother look at measures of forecast accuracyā, International Journal of Forecasting, Volume 22, Issue 4.</a><br> - <a href="https://arxiv.org/pdf/2110.13179.pdf">Kin G. Olivares, O. Nganba Meetei, Ruijun Ma, Rohan Reddy, Mengfei Cao, Lee Dicker. āProbabilistic Hierarchical Forecasting with Deep Poisson Mixtures. Submitted to the International Journal Forecasting, Working paper available at arxiv.</a></p> +</section> +</section> +<section id="mean-squared-scaled-error" class="level2"> +<h2 class="anchored" data-anchor-id="mean-squared-scaled-error">Mean Squared Scaled Error</h2> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/evaluation.py#L148" target="_blank" style="float:right; font-size:smaller">source</a></p> +<section id="msse" class="level3"> +<h3 class="anchored" data-anchor-id="msse">msse</h3> +<blockquote class="blockquote"> +<pre><code> msse (y, y_hat, y_train, mask=None)</code></pre> +</blockquote> +<p>Mean Squared Scaled Error</p> +<p>Computes Mean squared scaled error (MSSE), as proposed by Hyndman & Koehler (2006) as an alternative to percentage errors, to avoid measure unstability.</p> +<p><span class="math display">\[ \mathrm{MSSE}(\mathbf{y}, \mathbf{\hat{y}}, \mathbf{y}^{in-sample}) = +\frac{\frac{1}{h} \sum^{t+h}_{\tau=t+1} (y_{\tau} - \hat{y}_{\tau})^2}{\frac{1}{t-1} \sum^{t}_{\tau=2} (y_{\tau} - y_{\tau-1})^2},\]</span></p> +<p>where <span class="math inline">\(n\)</span> (<span class="math inline">\(n=\)</span><code>n</code>) is the size of the training data, and <span class="math inline">\(h\)</span> is the forecasting horizon (<span class="math inline">\(h=\)</span><code>horizon</code>).</p> +<p><strong>Parameters:</strong><br> <code>y</code>: numpy array, Actual values of size (<code>n_series</code>, <code>horizon</code>).<br> <code>y_hat</code>: numpy array, Predicted values (<code>n_series</code>, <code>horizon</code>).<br> <code>y_train</code>: numpy array, Predicted values (<code>n_series</code>, <code>n</code>).<br> <code>mask</code>: numpy array, Specifies date stamps per serie to consider in loss.<br></p> +<p><strong>Returns:</strong><br> <code>loss</code>: float.</p> +<p><strong>References:</strong><br> - <a href="https://www.sciencedirect.com/science/article/pii/S0169207006000239">Hyndman, R. J and Koehler, A. B. (2006). āAnother look at measures of forecast accuracyā, International Journal of Forecasting, Volume 22, Issue 4.</a><br></p> +</section> +</section> +<section id="scaled-crps" class="level2"> +<h2 class="anchored" data-anchor-id="scaled-crps">Scaled CRPS</h2> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/evaluation.py#L186" target="_blank" style="float:right; font-size:smaller">source</a></p> +<section id="scaled_crps" class="level3"> +<h3 class="anchored" data-anchor-id="scaled_crps">scaled_crps</h3> +<blockquote class="blockquote"> +<pre><code> scaled_crps (y, y_hat, quantiles)</code></pre> +</blockquote> +<p>Scaled Continues Ranked Probability Score</p> +<p>Calculates a scaled variation of the CRPS, as proposed by Rangapuram (2021), to measure the accuracy of predicted quantiles <code>y_hat</code> compared to the observation <code>y</code>.</p> +<p>This metric averages percentual weighted absolute deviations as defined by the quantile losses.</p> +<p><span class="math display">\[ \mathrm{sCRPS}(\hat{F}_{\tau}, \mathbf{y}_{\tau}) = \frac{2}{N} \sum_{i} +\int^{1}_{0} +\frac{\mathrm{QL}(\hat{F}_{i,\tau}, y_{i,\tau})_{q}}{\sum_{i} | y_{i,\tau} |} dq \]</span></p> +<p>where <span class="math inline">\(\hat{F}_{\tau}\)</span> is the an estimated multivariate distribution, and <span class="math inline">\(y_{i,\tau}\)</span> are its realizations.</p> +<p><strong>Parameters:</strong><br> <code>y</code>: numpy array, Actual values of size (<code>n_series</code>, <code>horizon</code>).<br> <code>y_hat</code>: numpy array, Predicted quantiles of size (<code>n_series</code>, <code>horizon</code>, <code>n_quantiles</code>).<br> <code>quantiles</code>: numpy array,(<code>n_quantiles</code>). Quantiles to estimate from the distribution of y.<br></p> +<p><strong>Returns:</strong><br> <code>loss</code>: float.</p> +<p><strong>References:</strong><br> - <a href="https://www.sciencedirect.com/science/article/pii/S0169207010000063">Gneiting, Tilmann. (2011). āQuantiles as optimal point forecastsā. International Journal of Forecasting.</a><br> - <a href="https://www.sciencedirect.com/science/article/pii/S0169207021001722">Spyros Makridakis, Evangelos Spiliotis, Vassilios Assimakopoulos, Zhi Chen, Anil Gaba, Ilia Tsetlin, Robert L. Winkler. (2022). āThe M5 uncertainty competition: Results, findings and conclusionsā. International Journal of Forecasting.</a><br> - <a href="https://proceedings.mlr.press/v139/rangapuram21a.html">Syama Sundar Rangapuram, Lucien D Werner, Konstantinos Benidis, Pedro Mercado, Jan Gasthaus, Tim Januschowski. (2021). āEnd-to-End Learning of Coherent Probabilistic Forecasts for Hierarchical Time Seriesā. Proceedings of the 38th International Conference on Machine Learning (ICML).</a></p> +</section> +</section> +<section id="energy-score" class="level2"> +<h2 class="anchored" data-anchor-id="energy-score">Energy Score</h2> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/evaluation.py#L227" target="_blank" style="float:right; font-size:smaller">source</a></p> +<section id="energy_score" class="level3"> +<h3 class="anchored" data-anchor-id="energy_score">energy_score</h3> +<blockquote class="blockquote"> +<pre><code> energy_score (y, y_sample1, y_sample2, beta=2)</code></pre> +</blockquote> +<p>Energy Score</p> +<p>Calculates Gneitingās Energy Score sample approximation for <code>y</code> and independent multivariate samples <code>y_sample1</code> and <code>y_sample2</code>. The Energy Score generalizes the CRPS (<code>beta</code>=1) in the multivariate setting.</p> +<p><span class="math display">\[ \mathrm{ES}(\mathbf{y}_{\tau}, \mathbf{\hat{y}}_{\tau}, \mathbf{\hat{y}}_{\tau}') += \frac{1}{2} \mathbb{E}_{\hat{P}} \left[ ||\mathbf{\hat{y}}_{\tau} - \mathbf{\hat{y}}_{\tau}'||^{\beta} \right] +- \mathbb{E}_{\hat{P}} \left[ ||\mathbf{y}_{\tau} - \mathbf{\hat{y}}_{\tau}||^{\beta} \right] +\quad \beta \in (0,2]\]</span></p> +<p>where <span class="math inline">\(\mathbf{\hat{y}}_{\tau}, \mathbf{\hat{y}}_{\tau}'\)</span> are independent samples drawn from <span class="math inline">\(\hat{P}\)</span>.</p> +<p><strong>Parameters:</strong><br> <code>y</code>: numpy array, Actual values of size (<code>n_series</code>, <code>horizon</code>).<br> <code>y_sample1</code>: numpy array, predictive distribution sample of size (<code>n_series</code>, <code>horizon</code>, <code>n_samples</code>).<br> <code>y_sample2</code>: numpy array, predictive distribution sample of size (<code>n_series</code>, <code>horizon</code>, <code>n_samples</code>).<br> <code>beta</code>: float in (0,2], defines the energy scoreās power for the euclidean metric.<br></p> +<p><strong>Returns:</strong><br> <code>score</code>: float.</p> +<p><strong>References:</strong><br> - <a href="https://sites.stat.washington.edu/raftery/Research/PDF/Gneiting2007jasa.pdf">Gneiting, Tilmann, and Adrian E. Raftery. (2007). āStrictly proper scoring rules, prediction and estimationā. Journal of the American Statistical Association.</a><br> - <a href="https://www.sciencedirect.com/science/article/pii/S0377221722006087">Anastasios Panagiotelis, Puwasala Gamakumara, George Athanasopoulos, Rob J. Hyndman. (2022). āProbabilistic forecast reconciliation: Properties, evaluation and score optimisationā. European Journal of Operational Research.</a></p> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/evaluation.py#L271" target="_blank" style="float:right; font-size:smaller">source</a></p> +</section> +<section id="log_score" class="level3"> +<h3 class="anchored" data-anchor-id="log_score">log_score</h3> +<blockquote class="blockquote"> +<pre><code> log_score (y, y_hat, cov, allow_singular=True)</code></pre> +</blockquote> +<p>Log Score.</p> +<p>One of the simplest multivariate probability scoring rules, it evaluates the negative density at the value of the realisation.</p> +<p><span class="math display">\[ \mathrm{LS}(\mathbf{y}_{\tau}, \mathbf{P}(\theta_{\tau})) += - \log(f(\mathbf{y}_{\tau}, \theta_{\tau}))\]</span></p> +<p>where <span class="math inline">\(f\)</span> is the density, <span class="math inline">\(\mathbf{P}(\theta_{\tau})\)</span> is a parametric distribution and <span class="math inline">\(f(\mathbf{y}_{\tau}, \theta_{\tau})\)</span> represents its density. For the moment we only support multivariate normal log score.</p> +<p><span class="math display">\[f(\mathbf{y}_{\tau}, \theta_{\tau}) = +(2\pi )^{-k/2}\det({\boldsymbol{\Sigma }})^{-1/2} +\,\exp \left( +-{\frac {1}{2}}(\mathbf{y}_{\tau} -\hat{\mathbf{y}}_{\tau})^{\!{\mathsf{T}}} +{\boldsymbol{\Sigma }}^{-1} +(\mathbf{y}_{\tau} -\hat{\mathbf{y}}_{\tau}) +\right)\]</span></p> +<p><strong>Parameters:</strong><br> <code>y</code>: numpy array, Actual values of size (<code>n_series</code>, <code>horizon</code>).<br> <code>y_hat</code>: numpy array, Predicted values (<code>n_series</code>, <code>horizon</code>).<br> <code>cov</code>: numpy matrix, Predicted values covariance (<code>n_series</code>, <code>n_series</code>, <code>horizon</code>).<br> <code>allow_singular</code>: bool=True, if true allows singular covariance.<br></p> +<p><strong>Returns:</strong><br> <code>score</code>: float.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb6"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a>x <span class="op">=</span> np.linspace(<span class="dv">0</span>, <span class="dv">5</span>, <span class="dv">10</span>, endpoint<span class="op">=</span><span class="va">False</span>)</span> +<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>y <span class="op">=</span> multivariate_normal.pdf(x, mean<span class="op">=</span><span class="fl">2.5</span>, cov<span class="op">=</span><span class="fl">0.5</span>)</span> +<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>y</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +</section> +</section> +</section> +<section id="hierarchical-evaluation" class="level1"> +<h1><span style="color:DarkBlue"> Hierarchical Evaluation </span></h1> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/evaluation.py#L309" target="_blank" style="float:right; font-size:smaller">source</a></p> +<section id="hierarchicalevaluation" class="level3"> +<h3 class="anchored" data-anchor-id="hierarchicalevaluation">HierarchicalEvaluation</h3> +<blockquote class="blockquote"> +<pre><code> HierarchicalEvaluation (evaluators:List[Callable])</code></pre> +</blockquote> +<p>Hierarchical Evaluation Class.</p> +<p>You can use your own metrics to evaluate the performance of each level in the structure. The metrics receive <code>y</code> and <code>y_hat</code> as arguments and they are numpy arrays of size <code>(series, horizon)</code>. Consider, for example, the function <code>rmse</code> that calculates the root mean squared error.</p> +<p>This class facilitates measurements across the hierarchy, defined by the <code>tags</code> list. See also the <a href="https://nixtla.github.io/hierarchicalforecast/utils.html#aggregate">aggregate method</a>.</p> +<p><strong>Parameters:</strong><br> <code>evaluators</code>: functions with arguments <code>y</code>, <code>y_hat</code> (numpy arrays).<br></p> +<p><strong>References:</strong><br></p> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/evaluation.py#L328" target="_blank" style="float:right; font-size:smaller">source</a></p> +</section> +<section id="hierarchicalevaluation.evaluate" class="level3"> +<h3 class="anchored" data-anchor-id="hierarchicalevaluation.evaluate">HierarchicalEvaluation.evaluate</h3> +<blockquote class="blockquote"> +<pre><code> HierarchicalEvaluation.evaluate (Y_hat_df:pandas.core.frame.DataFrame, + Y_test_df:pandas.core.frame.DataFrame, + tags:Dict[str,numpy.ndarray], Y_df:Optio + nal[pandas.core.frame.DataFrame]=None, + benchmark:Optional[str]=None)</code></pre> +</blockquote> +<p>Hierarchical Evaluation Method.</p> +<p><strong>Parameters:</strong><br> <code>Y_hat_df</code>: pd.DataFrame, Forecasts indexed by <code>'unique_id'</code> with column <code>'ds'</code> and models to evaluate.<br> <code>Y_test_df</code>: pd.DataFrame, True values with columns <code>['ds', 'y']</code>.<br> <code>tags</code>: np.array, each str key is a level and its value contains tags associated to that level.<br> <code>Y_df</code>: pd.DataFrame, Training set of base time series with columns <code>['ds', 'y']</code> indexed by <code>unique_id</code>.<br> <code>benchmark</code>: str, If passed, evaluators are scaled by the error of this benchark.<br></p> +<p><strong>Returns:</strong><br> <code>evaluation</code>: pd.DataFrame with accuracy measurements across hierarchical levels.</p> +</section> +</section> +<section id="example" class="level1"> +<h1><span style="color:DarkBlue"> Example </span></h1> +</section> +<section id="references" class="level1"> +<h1><span style="color:DarkBlue"> References </span></h1> +<ul> +<li><a href="https://sites.stat.washington.edu/raftery/Research/PDF/Gneiting2007jasa.pdf">Gneiting, Tilmann, and Adrian E. Raftery. (2007). "Strictly proper scoring rules, prediction and estimation". Journal of the American Statistical Association.</a></li> +<li><a href="https://www.sciencedirect.com/science/article/pii/S0169207010000063">Gneiting, Tilmann. (2011). "Quantiles as optimal point forecasts". International Journal of Forecasting.</a></li> +<li><a href="https://www.sciencedirect.com/science/article/pii/S0169207021001722">Spyros Makridakis, Evangelos Spiliotis, Vassilios Assimakopoulos, Zhi Chen, Anil Gaba, Ilia Tsetlin, Robert L. Winkler. (2022). "The M5 uncertainty competition: Results, findings and conclusions". International Journal of Forecasting.</a></li> +<li><a href="https://www.sciencedirect.com/science/article/pii/S0377221722006087">Anastasios Panagiotelis, Puwasala Gamakumara, George Athanasopoulos, Rob J. Hyndman. (2022). "Probabilistic forecast reconciliation: Properties, evaluation and score optimisation". European Journal of Operational Research.</a></li> +<li><a href="https://proceedings.mlr.press/v139/rangapuram21a.html">Syama Sundar Rangapuram, Lucien D Werner, Konstantinos Benidis, Pedro Mercado, Jan Gasthaus, Tim Januschowski. (2021). "End-to-End Learning of Coherent Probabilistic Forecasts for Hierarchical Time Series". Proceedings of the 38th International Conference on Machine Learning (ICML).</a></li> +<li><a href="https://arxiv.org/pdf/2110.13179.pdf">Kin G. Olivares, O. Nganba Meetei, Ruijun Ma, Rohan Reddy, Mengfei Cao, Lee Dicker (2022). āProbabilistic Hierarchical Forecasting with Deep Poisson Mixturesā. Submitted to the International Journal Forecasting, Working paper available at arxiv.</a></li> +<li><a href="https://www.sciencedirect.com/science/article/pii/S0169207021001874">Makridakis, S., Spiliotis E., and Assimakopoulos V. (2022). āM5 Accuracy Competition: Results, Findings, and Conclusions.ā, International Journal of Forecasting, Volume 38, Issue 4.</a></li> +</ul> + + +</section> + +<p>If you find the code useful, please ā us on <a href="https://github.com/nixtla/hierarchicalforecast">Github</a></p></main> <!-- /main --> +<script id="quarto-html-after-body" type="application/javascript"> +window.document.addEventListener("DOMContentLoaded", function (event) { + const toggleBodyColorMode = (bsSheetEl) => { + const mode = bsSheetEl.getAttribute("data-mode"); + const bodyEl = window.document.querySelector("body"); + if (mode === "dark") { + bodyEl.classList.add("quarto-dark"); + bodyEl.classList.remove("quarto-light"); + } else { + bodyEl.classList.add("quarto-light"); + bodyEl.classList.remove("quarto-dark"); + } + } + const toggleBodyColorPrimary = () => { + const bsSheetEl = window.document.querySelector("link#quarto-bootstrap"); + if (bsSheetEl) { + toggleBodyColorMode(bsSheetEl); + } + } + toggleBodyColorPrimary(); + const icon = "ī§"; + const anchorJS = new window.AnchorJS(); + anchorJS.options = { + placement: 'right', + icon: icon + }; + anchorJS.add('.anchored'); + const isCodeAnnotation = (el) => { + for (const clz of el.classList) { + if (clz.startsWith('code-annotation-')) { + return true; + } + } + return false; + } + const clipboard = new window.ClipboardJS('.code-copy-button', { + text: function(trigger) { + const codeEl = trigger.previousElementSibling.cloneNode(true); + for (const childEl of codeEl.children) { + if (isCodeAnnotation(childEl)) { + childEl.remove(); + } + } + return codeEl.innerText; + } + }); + clipboard.on('success', function(e) { + // button target + const button = e.trigger; + // don't keep focus + button.blur(); + // flash "checked" + button.classList.add('code-copy-button-checked'); + var currentTitle = button.getAttribute("title"); + button.setAttribute("title", "Copied!"); + let tooltip; + if (window.bootstrap) { + button.setAttribute("data-bs-toggle", "tooltip"); + button.setAttribute("data-bs-placement", "left"); + button.setAttribute("data-bs-title", "Copied!"); + tooltip = new bootstrap.Tooltip(button, + { trigger: "manual", + customClass: "code-copy-button-tooltip", + offset: [0, -8]}); + tooltip.show(); + } + setTimeout(function() { + if (tooltip) { + tooltip.hide(); + button.removeAttribute("data-bs-title"); + button.removeAttribute("data-bs-toggle"); + button.removeAttribute("data-bs-placement"); + } + button.setAttribute("title", currentTitle); + button.classList.remove('code-copy-button-checked'); + }, 1000); + // clear code selection + e.clearSelection(); + }); + function tippyHover(el, contentFn) { + const config = { + allowHTML: true, + content: contentFn, + maxWidth: 500, + delay: 100, + arrow: false, + appendTo: function(el) { + return el.parentElement; + }, + interactive: true, + interactiveBorder: 10, + theme: 'quarto', + placement: 'bottom-start' + }; + window.tippy(el, config); + } + const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]'); + for (var i=0; i<noterefs.length; i++) { + const ref = noterefs[i]; + tippyHover(ref, function() { + // use id or data attribute instead here + let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href'); + try { href = new URL(href).hash; } catch {} + const id = href.replace(/^#\/?/, ""); + const note = window.document.getElementById(id); + return note.innerHTML; + }); + } + let selectedAnnoteEl; + const selectorForAnnotation = ( cell, annotation) => { + let cellAttr = 'data-code-cell="' + cell + '"'; + let lineAttr = 'data-code-annotation="' + annotation + '"'; + const selector = 'span[' + cellAttr + '][' + lineAttr + ']'; + return selector; + } + const selectCodeLines = (annoteEl) => { + const doc = window.document; + const targetCell = annoteEl.getAttribute("data-target-cell"); + const targetAnnotation = annoteEl.getAttribute("data-target-annotation"); + const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation)); + const lines = annoteSpan.getAttribute("data-code-lines").split(","); + const lineIds = lines.map((line) => { + return targetCell + "-" + line; + }) + let top = null; + let height = null; + let parent = null; + if (lineIds.length > 0) { + //compute the position of the single el (top and bottom and make a div) + const el = window.document.getElementById(lineIds[0]); + top = el.offsetTop; + height = el.offsetHeight; + parent = el.parentElement.parentElement; + if (lineIds.length > 1) { + const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]); + const bottom = lastEl.offsetTop + lastEl.offsetHeight; + height = bottom - top; + } + if (top !== null && height !== null && parent !== null) { + // cook up a div (if necessary) and position it + let div = window.document.getElementById("code-annotation-line-highlight"); + if (div === null) { + div = window.document.createElement("div"); + div.setAttribute("id", "code-annotation-line-highlight"); + div.style.position = 'absolute'; + parent.appendChild(div); + } + div.style.top = top - 2 + "px"; + div.style.height = height + 4 + "px"; + let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter"); + if (gutterDiv === null) { + gutterDiv = window.document.createElement("div"); + gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter"); + gutterDiv.style.position = 'absolute'; + const codeCell = window.document.getElementById(targetCell); + const gutter = codeCell.querySelector('.code-annotation-gutter'); + gutter.appendChild(gutterDiv); + } + gutterDiv.style.top = top - 2 + "px"; + gutterDiv.style.height = height + 4 + "px"; + } + selectedAnnoteEl = annoteEl; + } + }; + const unselectCodeLines = () => { + const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"]; + elementsIds.forEach((elId) => { + const div = window.document.getElementById(elId); + if (div) { + div.remove(); + } + }); + selectedAnnoteEl = undefined; + }; + // Attach click handler to the DT + const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); + for (const annoteDlNode of annoteDls) { + annoteDlNode.addEventListener('click', (event) => { + const clickedEl = event.target; + if (clickedEl !== selectedAnnoteEl) { + unselectCodeLines(); + const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active'); + if (activeEl) { + activeEl.classList.remove('code-annotation-active'); + } + selectCodeLines(clickedEl); + clickedEl.classList.add('code-annotation-active'); + } else { + // Unselect the line + unselectCodeLines(); + clickedEl.classList.remove('code-annotation-active'); + } + }); + } + const findCites = (el) => { + const parentEl = el.parentElement; + if (parentEl) { + const cites = parentEl.dataset.cites; + if (cites) { + return { + el, + cites: cites.split(' ') + }; + } else { + return findCites(el.parentElement) + } + } else { + return undefined; + } + }; + var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]'); + for (var i=0; i<bibliorefs.length; i++) { + const ref = bibliorefs[i]; + const citeInfo = findCites(ref); + if (citeInfo) { + tippyHover(citeInfo.el, function() { + var popup = window.document.createElement('div'); + citeInfo.cites.forEach(function(cite) { + var citeDiv = window.document.createElement('div'); + citeDiv.classList.add('hanging-indent'); + citeDiv.classList.add('csl-entry'); + var biblioDiv = window.document.getElementById('ref-' + cite); + if (biblioDiv) { + citeDiv.innerHTML = biblioDiv.innerHTML; + } + popup.appendChild(citeDiv); + }); + return popup.innerHTML; + }); + } + } +}); +</script> +</div> <!-- /content --> + + + +</body></html> \ No newline at end of file diff --git a/examples/AustralianDomesticTourism-Bootstraped-Intervals_files/figure-html/cell-11-output-1.png b/examples/AustralianDomesticTourism-Bootstraped-Intervals_files/figure-html/cell-11-output-1.png new file mode 100644 index 00000000..67e3d30d Binary files /dev/null and b/examples/AustralianDomesticTourism-Bootstraped-Intervals_files/figure-html/cell-11-output-1.png differ diff --git a/examples/AustralianDomesticTourism-Bootstraped-Intervals_files/figure-html/cell-12-output-1.png b/examples/AustralianDomesticTourism-Bootstraped-Intervals_files/figure-html/cell-12-output-1.png new file mode 100644 index 00000000..a79719f9 Binary files /dev/null and b/examples/AustralianDomesticTourism-Bootstraped-Intervals_files/figure-html/cell-12-output-1.png differ diff --git a/examples/AustralianDomesticTourism-Bootstraped-Intervals_files/figure-html/cell-20-output-1.png b/examples/AustralianDomesticTourism-Bootstraped-Intervals_files/figure-html/cell-20-output-1.png new file mode 100644 index 00000000..d333e10d Binary files /dev/null and b/examples/AustralianDomesticTourism-Bootstraped-Intervals_files/figure-html/cell-20-output-1.png differ diff --git a/examples/AustralianDomesticTourism-Bootstraped-Intervals_files/figure-html/cell-21-output-1.png b/examples/AustralianDomesticTourism-Bootstraped-Intervals_files/figure-html/cell-21-output-1.png new file mode 100644 index 00000000..73dffde2 Binary files /dev/null and b/examples/AustralianDomesticTourism-Bootstraped-Intervals_files/figure-html/cell-21-output-1.png differ diff --git a/examples/AustralianDomesticTourism-Bootstraped-Intervals_files/figure-html/cell-22-output-1.png b/examples/AustralianDomesticTourism-Bootstraped-Intervals_files/figure-html/cell-22-output-1.png new file mode 100644 index 00000000..292f8538 Binary files /dev/null and b/examples/AustralianDomesticTourism-Bootstraped-Intervals_files/figure-html/cell-22-output-1.png differ diff --git a/examples/AustralianDomesticTourism-Bootstraped-Intervals_files/figure-html/cell-23-output-1.png b/examples/AustralianDomesticTourism-Bootstraped-Intervals_files/figure-html/cell-23-output-1.png new file mode 100644 index 00000000..21f2d6de Binary files /dev/null and b/examples/AustralianDomesticTourism-Bootstraped-Intervals_files/figure-html/cell-23-output-1.png differ diff --git a/examples/AustralianDomesticTourism-Intervals_files/figure-html/cell-11-output-1.png b/examples/AustralianDomesticTourism-Intervals_files/figure-html/cell-11-output-1.png new file mode 100644 index 00000000..67e3d30d Binary files /dev/null and b/examples/AustralianDomesticTourism-Intervals_files/figure-html/cell-11-output-1.png differ diff --git a/examples/AustralianDomesticTourism-Intervals_files/figure-html/cell-12-output-1.png b/examples/AustralianDomesticTourism-Intervals_files/figure-html/cell-12-output-1.png new file mode 100644 index 00000000..a79719f9 Binary files /dev/null and b/examples/AustralianDomesticTourism-Intervals_files/figure-html/cell-12-output-1.png differ diff --git a/examples/AustralianDomesticTourism-Intervals_files/figure-html/cell-20-output-1.png b/examples/AustralianDomesticTourism-Intervals_files/figure-html/cell-20-output-1.png new file mode 100644 index 00000000..7df65727 Binary files /dev/null and b/examples/AustralianDomesticTourism-Intervals_files/figure-html/cell-20-output-1.png differ diff --git a/examples/AustralianDomesticTourism-Intervals_files/figure-html/cell-21-output-1.png b/examples/AustralianDomesticTourism-Intervals_files/figure-html/cell-21-output-1.png new file mode 100644 index 00000000..0d68892a Binary files /dev/null and b/examples/AustralianDomesticTourism-Intervals_files/figure-html/cell-21-output-1.png differ diff --git a/examples/AustralianDomesticTourism-Intervals_files/figure-html/cell-22-output-1.png b/examples/AustralianDomesticTourism-Intervals_files/figure-html/cell-22-output-1.png new file mode 100644 index 00000000..27e2b0e6 Binary files /dev/null and b/examples/AustralianDomesticTourism-Intervals_files/figure-html/cell-22-output-1.png differ diff --git a/examples/AustralianDomesticTourism-Intervals_files/figure-html/cell-23-output-1.png b/examples/AustralianDomesticTourism-Intervals_files/figure-html/cell-23-output-1.png new file mode 100644 index 00000000..e8c33ae8 Binary files /dev/null and b/examples/AustralianDomesticTourism-Intervals_files/figure-html/cell-23-output-1.png differ diff --git a/examples/AustralianDomesticTourism-Permbu-Intervals_files/figure-html/cell-11-output-1.png b/examples/AustralianDomesticTourism-Permbu-Intervals_files/figure-html/cell-11-output-1.png new file mode 100644 index 00000000..52a7471c Binary files /dev/null and b/examples/AustralianDomesticTourism-Permbu-Intervals_files/figure-html/cell-11-output-1.png differ diff --git a/examples/AustralianDomesticTourism-Permbu-Intervals_files/figure-html/cell-12-output-1.png b/examples/AustralianDomesticTourism-Permbu-Intervals_files/figure-html/cell-12-output-1.png new file mode 100644 index 00000000..628eb0b1 Binary files /dev/null and b/examples/AustralianDomesticTourism-Permbu-Intervals_files/figure-html/cell-12-output-1.png differ diff --git a/examples/AustralianDomesticTourism-Permbu-Intervals_files/figure-html/cell-20-output-1.png b/examples/AustralianDomesticTourism-Permbu-Intervals_files/figure-html/cell-20-output-1.png new file mode 100644 index 00000000..eabac5d3 Binary files /dev/null and b/examples/AustralianDomesticTourism-Permbu-Intervals_files/figure-html/cell-20-output-1.png differ diff --git a/examples/AustralianDomesticTourism-Permbu-Intervals_files/figure-html/cell-21-output-1.png b/examples/AustralianDomesticTourism-Permbu-Intervals_files/figure-html/cell-21-output-1.png new file mode 100644 index 00000000..7b6dae0b Binary files /dev/null and b/examples/AustralianDomesticTourism-Permbu-Intervals_files/figure-html/cell-21-output-1.png differ diff --git a/examples/AustralianDomesticTourism-Permbu-Intervals_files/figure-html/cell-22-output-1.png b/examples/AustralianDomesticTourism-Permbu-Intervals_files/figure-html/cell-22-output-1.png new file mode 100644 index 00000000..4e335ee0 Binary files /dev/null and b/examples/AustralianDomesticTourism-Permbu-Intervals_files/figure-html/cell-22-output-1.png differ diff --git a/examples/MLFrameworksExample_files/figure-html/cell-15-output-1.png b/examples/MLFrameworksExample_files/figure-html/cell-15-output-1.png new file mode 100644 index 00000000..b6b58987 Binary files /dev/null and b/examples/MLFrameworksExample_files/figure-html/cell-15-output-1.png differ diff --git a/examples/MLFrameworksExample_files/figure-html/cell-16-output-1.png b/examples/MLFrameworksExample_files/figure-html/cell-16-output-1.png new file mode 100644 index 00000000..d1a34c56 Binary files /dev/null and b/examples/MLFrameworksExample_files/figure-html/cell-16-output-1.png differ diff --git a/examples/MLFrameworksExample_files/figure-html/cell-6-output-1.png b/examples/MLFrameworksExample_files/figure-html/cell-6-output-1.png new file mode 100644 index 00000000..dbd2c691 Binary files /dev/null and b/examples/MLFrameworksExample_files/figure-html/cell-6-output-1.png differ diff --git a/examples/TourismLarge-Evaluation_files/figure-html/cell-13-output-1.png b/examples/TourismLarge-Evaluation_files/figure-html/cell-13-output-1.png new file mode 100644 index 00000000..859d5f27 Binary files /dev/null and b/examples/TourismLarge-Evaluation_files/figure-html/cell-13-output-1.png differ diff --git a/examples/TourismLarge-Evaluation_files/figure-html/cell-7-output-1.png b/examples/TourismLarge-Evaluation_files/figure-html/cell-7-output-1.png new file mode 100644 index 00000000..15bc8d4b Binary files /dev/null and b/examples/TourismLarge-Evaluation_files/figure-html/cell-7-output-1.png differ diff --git a/examples/australiandomestictourism-bootstraped-intervals.html b/examples/australiandomestictourism-bootstraped-intervals.html new file mode 100644 index 00000000..038540de --- /dev/null +++ b/examples/australiandomestictourism-bootstraped-intervals.html @@ -0,0 +1,1249 @@ +<!DOCTYPE html> +<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head> + +<meta charset="utf-8"> +<meta name="generator" content="quarto-1.3.450"> + +<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes"> + + +<title>hierarchicalforecast - Bootstrap</title> +<style> +code{white-space: pre-wrap;} +span.smallcaps{font-variant: small-caps;} +div.columns{display: flex; gap: min(4vw, 1.5em);} +div.column{flex: auto; overflow-x: auto;} +div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;} +ul.task-list{list-style: none;} +ul.task-list li input[type="checkbox"] { + width: 0.8em; + margin: 0 0.8em 0.2em -1em; /* quarto-specific, see https://github.com/quarto-dev/quarto-cli/issues/4556 */ + vertical-align: middle; +} +/* CSS for syntax highlighting */ +pre > code.sourceCode { white-space: pre; position: relative; } +pre > code.sourceCode > span { display: inline-block; line-height: 1.25; } +pre > code.sourceCode > span:empty { height: 1.2em; } +.sourceCode { overflow: visible; } +code.sourceCode > span { color: inherit; text-decoration: inherit; } +div.sourceCode { margin: 1em 0; } +pre.sourceCode { margin: 0; } +@media screen { +div.sourceCode { overflow: auto; } +} +@media print { +pre > code.sourceCode { white-space: pre-wrap; } +pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; } +} +pre.numberSource code + { counter-reset: source-line 0; } +pre.numberSource code > span + { position: relative; left: -4em; counter-increment: source-line; } +pre.numberSource code > span > a:first-child::before + { content: counter(source-line); + position: relative; left: -1em; text-align: right; vertical-align: baseline; + border: none; display: inline-block; + -webkit-touch-callout: none; -webkit-user-select: none; + -khtml-user-select: none; -moz-user-select: none; + -ms-user-select: none; user-select: none; + padding: 0 4px; width: 4em; + } +pre.numberSource { margin-left: 3em; padding-left: 4px; } +div.sourceCode + { } +@media screen { +pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; } +} +</style> + + +<script src="../site_libs/quarto-nav/quarto-nav.js"></script> +<script src="../site_libs/quarto-nav/headroom.min.js"></script> +<script src="../site_libs/clipboard/clipboard.min.js"></script> +<script src="../site_libs/quarto-search/autocomplete.umd.js"></script> +<script src="../site_libs/quarto-search/fuse.min.js"></script> +<script src="../site_libs/quarto-search/quarto-search.js"></script> +<meta name="quarto:offset" content="../"> +<link href="../favicon_png.png" rel="icon" type="image/png"> +<script src="../site_libs/quarto-html/quarto.js"></script> +<script src="../site_libs/quarto-html/popper.min.js"></script> +<script src="../site_libs/quarto-html/tippy.umd.min.js"></script> +<script src="../site_libs/quarto-html/anchor.min.js"></script> +<link href="../site_libs/quarto-html/tippy.css" rel="stylesheet"> +<link href="../site_libs/quarto-html/quarto-syntax-highlighting.css" rel="stylesheet" id="quarto-text-highlighting-styles"> +<script src="../site_libs/bootstrap/bootstrap.min.js"></script> +<link href="../site_libs/bootstrap/bootstrap-icons.css" rel="stylesheet"> +<link href="../site_libs/bootstrap/bootstrap.min.css" rel="stylesheet" id="quarto-bootstrap" data-mode="light"> +<script id="quarto-search-options" type="application/json">{ + "location": "navbar", + "copy-button": false, + "collapse-after": 3, + "panel-placement": "end", + "type": "overlay", + "limit": 20, + "language": { + "search-no-results-text": "No results", + "search-matching-documents-text": "matching documents", + "search-copy-link-title": "Copy link to search", + "search-hide-matches-text": "Hide additional matches", + "search-more-match-text": "more match in this document", + "search-more-matches-text": "more matches in this document", + "search-clear-button-title": "Clear", + "search-detached-cancel-button-title": "Cancel", + "search-submit-button-title": "Submit", + "search-label": "Search" + } +}</script> +<script async="" src="https://www.googletagmanager.com/gtag/js?id=G-NXJNCVR18L"></script> + +<script type="text/javascript"> + +window.dataLayer = window.dataLayer || []; +function gtag(){dataLayer.push(arguments);} +gtag('js', new Date()); +gtag('config', 'G-NXJNCVR18L', { 'anonymize_ip': true}); +</script> +<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js" integrity="sha512-c3Nl8+7g4LMSTdrm621y7kf9v3SDPnhxLNhcjFJbKECVnmZHTdo+IRO05sNLTH/D3vA6u1X32ehoLC7WFVdheg==" crossorigin="anonymous"></script> +<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js" integrity="sha512-bLT0Qm9VnAYZDflyKcBaQ2gg0hSYNQrJ8RilYldYQ1FxQYoCLtUjuuRuZo+fjqhx/qtq/1itJ0C2ejDxltZVFg==" crossorigin="anonymous"></script> +<script type="application/javascript">define('jquery', [],function() {return window.jQuery;})</script> + + <script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script> + <script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml-full.js" type="text/javascript"></script> + +<link rel="stylesheet" href="../styles.css"> +<meta property="og:title" content="hierarchicalforecast - Bootstrap"> +<meta property="og:description" content=""> +<meta property="og:image" content="https://colab.research.google.com/assets/colab-badge.svg"> +<meta property="og:site-name" content="hierarchicalforecast"> +<meta name="twitter:title" content="hierarchicalforecast - Bootstrap"> +<meta name="twitter:description" content=""> +<meta name="twitter:image" content="https://colab.research.google.com/assets/colab-badge.svg"> +<meta name="twitter:card" content="summary_large_image"> +</head> + +<body class="nav-sidebar floating nav-fixed"> + +<div id="quarto-search-results"></div> + <header id="quarto-header" class="headroom fixed-top"> + <nav class="navbar navbar-expand-lg navbar-dark "> + <div class="navbar-container container-fluid"> + <div class="navbar-brand-container"> + <a class="navbar-brand" href="../index.html"> + <span class="navbar-title">hierarchicalforecast</span> + </a> + </div> + <div id="quarto-search" class="" title="Search"></div> + <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + <span class="navbar-toggler-icon"></span> +</button> + <div class="collapse navbar-collapse" id="navbarCollapse"> + <ul class="navbar-nav navbar-nav-scroll me-auto"> + <li class="nav-item"> + <a class="nav-link active" href="../examples/tourismsmall.html" rel="" target="" aria-current="page"> + <span class="menu-text">Get Started</span></a> + </li> + <li class="nav-item dropdown "> + <a class="nav-link dropdown-toggle" href="#" id="nav-menu-nixtlaverse" role="button" data-bs-toggle="dropdown" aria-expanded="false" rel="" target=""> + <span class="menu-text">NixtlaVerse</span> + </a> + <ul class="dropdown-menu" aria-labelledby="nav-menu-nixtlaverse"> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/mlforecast" rel="" target=""> + <span class="dropdown-text">MLForecast š¤</span></a> + </li> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/neuralforecast" rel="" target=""> + <span class="dropdown-text">NeuralForecast š§ </span></a> + </li> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/statsforecast" rel="" target=""> + <span class="dropdown-text">StatsForecast ā”ļø</span></a> + </li> + </ul> + </li> + <li class="nav-item dropdown "> + <a class="nav-link dropdown-toggle" href="#" id="nav-menu-help" role="button" data-bs-toggle="dropdown" aria-expanded="false" rel="" target=""> + <span class="menu-text">Help</span> + </a> + <ul class="dropdown-menu" aria-labelledby="nav-menu-help"> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/hierarchicalforecast/issues/new/choose" rel="" target=""><i class="bi bi-bug" role="img"> +</i> + <span class="dropdown-text">Report an Issue</span></a> + </li> + <li> + <a class="dropdown-item" href="https://join.slack.com/t/nixtlacommunity/shared_invite/zt-1kd5m5db7-7OOfy0xVNf1PcvCiAPWvPw" rel="" target=""><i class="bi bi-chat-right-text" role="img"> +</i> + <span class="dropdown-text">Join our Slack</span></a> + </li> + </ul> + </li> +</ul> + <ul class="navbar-nav navbar-nav-scroll ms-auto"> + <li class="nav-item compact"> + <a class="nav-link" href="https://github.com/nixtla/hierarchicalforecast" rel="" target=""><i class="bi bi-github" role="img"> +</i> + <span class="menu-text"></span></a> + </li> + <li class="nav-item compact"> + <a class="nav-link" href="https://twitter.com/nixtlainc" rel="" target=""><i class="bi bi-twitter" role="img" aria-label="Nixtla Twitter"> +</i> + <span class="menu-text"></span></a> + </li> +</ul> + <div class="quarto-navbar-tools"> +</div> + </div> <!-- /navcollapse --> + </div> <!-- /container-fluid --> + </nav> + <nav class="quarto-secondary-nav"> + <div class="container-fluid d-flex"> + <button type="button" class="quarto-btn-toggle btn" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + <i class="bi bi-layout-text-sidebar-reverse"></i> + </button> + <nav class="quarto-page-breadcrumbs" aria-label="breadcrumb"><ol class="breadcrumb"><li class="breadcrumb-item">Tutorials</li><li class="breadcrumb-item"><a href="../examples/australiandomestictourism-intervals.html">Probabilistic Reconciliation</a></li><li class="breadcrumb-item"><a href="../examples/australiandomestictourism-bootstraped-intervals.html">Bootstrap</a></li></ol></nav> + <a class="flex-grow-1" role="button" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + </a> + </div> + </nav> +</header> +<!-- content --> +<div id="quarto-content" class="quarto-container page-columns page-rows-contents page-layout-article page-navbar"> +<!-- sidebar --> + <nav id="quarto-sidebar" class="sidebar collapse collapse-horizontal sidebar-navigation floating overflow-auto"> + <div class="sidebar-menu-container"> + <ul class="list-unstyled mt-1"> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../index.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Hierarchical Forecast š</span></a> + </div> +</li> + <li class="px-0"><hr class="sidebar-divider hi "></li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-1" aria-expanded="false"> + <span class="menu-text">Getting Started</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-1" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-1" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/installation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Install</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/tourismsmall.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Reconciliation Quick Start</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/introduction.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Introduction</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-2" aria-expanded="true"> + <span class="menu-text">Tutorials</span></a> + <a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-2" aria-expanded="true" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-2" class="collapse list-unstyled sidebar-section depth1 show"> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-3" aria-expanded="false"> + <span class="menu-text">Point Reconciliation</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-3" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-3" class="collapse list-unstyled sidebar-section depth2 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Geographical Aggregation (Tourism)</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australianprisonpopulation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Geographical Aggregation (Prison Population)</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/nonnegativereconciliation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Non-Negative MinTrace</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-4" aria-expanded="true"> + <span class="menu-text">Probabilistic Reconciliation</span></a> + <a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-4" aria-expanded="true" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-4" class="collapse list-unstyled sidebar-section depth2 show"> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Normality</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism-bootstraped-intervals.html" class="sidebar-item-text sidebar-link active"> + <span class="menu-text">Bootstrap</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism-permbu-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">PERMBU</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/tourismlarge-evaluation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Probabilistic Forecast Evaluation</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-5" aria-expanded="false"> + <span class="menu-text">ML Forecast Reconciliation</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-5" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-5" class="collapse list-unstyled sidebar-section depth2 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/hierarchicalforecast-gluonts.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">GluonTS</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/mlframeworksexample.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Neural/MLForecast</span></a> + </div> +</li> + </ul> + </li> + </ul> + </li> + <li class="sidebar-item"> + <span class="menu-text">Methods</span> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-6" aria-expanded="false"> + <span class="menu-text">API Reference</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-6" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-6" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../core.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Core </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../methods.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Reconciliation Methods </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../probabilistic_methods.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Probabilistic Methods </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../evaluation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Hierarchical Evaluation</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../utils.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Aggregation/Visualization Utils</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-7" aria-expanded="false"> + <span class="menu-text">Community</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-7" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-7" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item"> + <span class="menu-text">Contributing</span> + </li> + </ul> + </li> + </ul> + </div> +</nav> +<div id="quarto-sidebar-glass" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass"></div> +<!-- margin-sidebar --> + <div id="quarto-margin-sidebar" class="sidebar margin-sidebar"> + <nav id="TOC" role="doc-toc" class="toc-active"> + <h2 id="toc-title">On this page</h2> + + <ul> + <li><a href="#aggregate-bottom-time-series" id="toc-aggregate-bottom-time-series" class="nav-link active" data-scroll-target="#aggregate-bottom-time-series">Aggregate bottom time series</a> + <ul class="collapse"> + <li><a href="#split-traintest-sets" id="toc-split-traintest-sets" class="nav-link" data-scroll-target="#split-traintest-sets">Split Train/Test sets</a></li> + </ul></li> + <li><a href="#computing-base-forecasts" id="toc-computing-base-forecasts" class="nav-link" data-scroll-target="#computing-base-forecasts">Computing Base Forecasts</a></li> + <li><a href="#reconcile-base-forecasts" id="toc-reconcile-base-forecasts" class="nav-link" data-scroll-target="#reconcile-base-forecasts">Reconcile Base Forecasts</a></li> + <li><a href="#plot-predictions" id="toc-plot-predictions" class="nav-link" data-scroll-target="#plot-predictions">Plot Predictions</a> + <ul class="collapse"> + <li><a href="#plot-single-time-series" id="toc-plot-single-time-series" class="nav-link" data-scroll-target="#plot-single-time-series">Plot single time series</a></li> + <li><a href="#plot-hierarchichally-linked-time-series" id="toc-plot-hierarchichally-linked-time-series" class="nav-link" data-scroll-target="#plot-hierarchichally-linked-time-series">Plot hierarchichally linked time series</a></li> + <li><a href="#references" id="toc-references" class="nav-link" data-scroll-target="#references">References</a></li> + </ul></li> + </ul> +<div class="toc-actions"><div><i class="bi bi-github"></i></div><div class="action-links"><p><a href="https://github.com/Nixtla/hierarchicalforecast/issues/new" class="toc-action">Report an issue</a></p></div></div></nav> + </div> +<!-- main --> +<main class="content" id="quarto-document-content"> + +<header id="title-block-header" class="quarto-title-block default"> +<div class="quarto-title"> +<h1 class="title">Bootstrap</h1> +</div> + + + +<div class="quarto-title-meta"> + + + + + </div> + + +</header> + +<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! --> +<p><a href="https://colab.research.google.com/github/Nixtla/hierarchicalforecast/blob/main/nbs/examples/AustralianDomesticTourism-Bootstraped-Intervals.ipynb" target="_parent"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"></a></p> +<p>In many cases, only the time series at the lowest level of the hierarchies (bottom time series) are available. <code>HierarchicalForecast</code> has tools to create time series for all hierarchies and also allows you to calculate prediction intervals for all hierarchies. In this notebook we will see how to do it.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb1"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="op">!</span>pip install hierarchicalforecast statsforecast</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb2"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> numpy <span class="im">as</span> np</span> +<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> pandas <span class="im">as</span> pd</span> +<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> matplotlib.pyplot <span class="im">as</span> plt</span> +<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a><span class="co"># compute base forecast no coherent</span></span> +<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> statsforecast.models <span class="im">import</span> ETS, Naive</span> +<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> statsforecast.core <span class="im">import</span> StatsForecast</span> +<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a><span class="co">#obtain hierarchical reconciliation methods and evaluation</span></span> +<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> hierarchicalforecast.methods <span class="im">import</span> BottomUp, MinTrace</span> +<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> hierarchicalforecast.utils <span class="im">import</span> aggregate, HierarchicalPlot</span> +<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> hierarchicalforecast.core <span class="im">import</span> HierarchicalReconciliation</span> +<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> hierarchicalforecast.evaluation <span class="im">import</span> HierarchicalEvaluation</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-stderr"> +<pre><code>/Users/fedex/miniconda3/envs/hierarchicalforecast/lib/python3.10/site-packages/statsforecast/core.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html + from tqdm.autonotebook import tqdm</code></pre> +</div> +</div> +<section id="aggregate-bottom-time-series" class="level2"> +<h2 class="anchored" data-anchor-id="aggregate-bottom-time-series">Aggregate bottom time series</h2> +<p>In this example we will use the <a href="https://otexts.com/fpp3/tourism.html">Tourism</a> dataset from the <a href="https://otexts.com/fpp3/">Forecasting: Principles and Practice</a> book. The dataset only contains the time series at the lowest level, so we need to create the time series for all hierarchies.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb4"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a>Y_df <span class="op">=</span> pd.read_csv(<span class="st">'https://raw.githubusercontent.com/Nixtla/transfer-learning-time-series/main/datasets/tourism.csv'</span>)</span> +<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>Y_df <span class="op">=</span> Y_df.rename({<span class="st">'Trips'</span>: <span class="st">'y'</span>, <span class="st">'Quarter'</span>: <span class="st">'ds'</span>}, axis<span class="op">=</span><span class="dv">1</span>)</span> +<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>Y_df.insert(<span class="dv">0</span>, <span class="st">'Country'</span>, <span class="st">'Australia'</span>)</span> +<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>Y_df <span class="op">=</span> Y_df[[<span class="st">'Country'</span>, <span class="st">'Region'</span>, <span class="st">'State'</span>, <span class="st">'Purpose'</span>, <span class="st">'ds'</span>, <span class="st">'y'</span>]]</span> +<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>Y_df[<span class="st">'ds'</span>] <span class="op">=</span> Y_df[<span class="st">'ds'</span>].<span class="bu">str</span>.replace(<span class="vs">r'(\d+) (Q\d)'</span>, <span class="vs">r'\1-\2'</span>, regex<span class="op">=</span><span class="va">True</span>)</span> +<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>Y_df[<span class="st">'ds'</span>] <span class="op">=</span> pd.to_datetime(Y_df[<span class="st">'ds'</span>])</span> +<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>Y_df.head()</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<div> + + +<table class="dataframe table table-sm table-striped small" data-quarto-postprocess="true" data-border="1"> +<thead> +<tr class="header"> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th">Country</th> +<th data-quarto-table-cell-role="th">Region</th> +<th data-quarto-table-cell-role="th">State</th> +<th data-quarto-table-cell-role="th">Purpose</th> +<th data-quarto-table-cell-role="th">ds</th> +<th data-quarto-table-cell-role="th">y</th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td data-quarto-table-cell-role="th">0</td> +<td>Australia</td> +<td>Adelaide</td> +<td>South Australia</td> +<td>Business</td> +<td>1998-01-01</td> +<td>135.077690</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">1</td> +<td>Australia</td> +<td>Adelaide</td> +<td>South Australia</td> +<td>Business</td> +<td>1998-04-01</td> +<td>109.987316</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">2</td> +<td>Australia</td> +<td>Adelaide</td> +<td>South Australia</td> +<td>Business</td> +<td>1998-07-01</td> +<td>166.034687</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">3</td> +<td>Australia</td> +<td>Adelaide</td> +<td>South Australia</td> +<td>Business</td> +<td>1998-10-01</td> +<td>127.160464</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">4</td> +<td>Australia</td> +<td>Adelaide</td> +<td>South Australia</td> +<td>Business</td> +<td>1999-01-01</td> +<td>137.448533</td> +</tr> +</tbody> +</table> + +</div> +</div> +</div> +<p>The dataset can be grouped in the following non-strictly hierarchical structure.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb5"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a>spec <span class="op">=</span> [</span> +<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a> [<span class="st">'Country'</span>],</span> +<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a> [<span class="st">'Country'</span>, <span class="st">'State'</span>], </span> +<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a> [<span class="st">'Country'</span>, <span class="st">'Purpose'</span>], </span> +<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a> [<span class="st">'Country'</span>, <span class="st">'State'</span>, <span class="st">'Region'</span>], </span> +<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a> [<span class="st">'Country'</span>, <span class="st">'State'</span>, <span class="st">'Purpose'</span>], </span> +<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a> [<span class="st">'Country'</span>, <span class="st">'State'</span>, <span class="st">'Region'</span>, <span class="st">'Purpose'</span>]</span> +<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a>]</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<p>Using the <a href="https://Nixtla.github.io/hierarchicalforecast/utils.html#aggregate"><code>aggregate</code></a> function from <code>HierarchicalForecast</code> we can generate: 1. <code>Y_df</code>: the hierarchical structured series <span class="math inline">\(\mathbf{y}_{[a,b]\tau}\)</span> 2. <code>S_df</code>: the aggregation constraings dataframe with <span class="math inline">\(S_{[a,b]}\)</span> 3. <code>tags</code>: a list with the āunique_idsā conforming each aggregation level.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb6"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a>Y_df, S_df, tags <span class="op">=</span> aggregate(df<span class="op">=</span>Y_df, spec<span class="op">=</span>spec)</span> +<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>Y_df <span class="op">=</span> Y_df.reset_index()</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-stderr"> +<pre><code>/Users/fedex/miniconda3/envs/hierarchicalforecast/lib/python3.10/site-packages/sklearn/preprocessing/_encoders.py:828: FutureWarning: `sparse` was renamed to `sparse_output` in version 1.2 and will be removed in 1.4. `sparse_output` is ignored unless you leave `sparse` to its default value. + warnings.warn(</code></pre> +</div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb8"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a>Y_df.head()</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<div> + + +<table class="dataframe table table-sm table-striped small" data-quarto-postprocess="true" data-border="1"> +<thead> +<tr class="header"> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th">unique_id</th> +<th data-quarto-table-cell-role="th">ds</th> +<th data-quarto-table-cell-role="th">y</th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td data-quarto-table-cell-role="th">0</td> +<td>Australia</td> +<td>1998-01-01</td> +<td>23182.197269</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">1</td> +<td>Australia</td> +<td>1998-04-01</td> +<td>20323.380067</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">2</td> +<td>Australia</td> +<td>1998-07-01</td> +<td>19826.640511</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">3</td> +<td>Australia</td> +<td>1998-10-01</td> +<td>20830.129891</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">4</td> +<td>Australia</td> +<td>1999-01-01</td> +<td>22087.353380</td> +</tr> +</tbody> +</table> + +</div> +</div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb9"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a>S_df.iloc[:<span class="dv">5</span>, :<span class="dv">5</span>]</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<div> + + +<table class="dataframe table table-sm table-striped small" data-quarto-postprocess="true" data-border="1"> +<thead> +<tr class="header"> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th">Australia/ACT/Canberra/Business</th> +<th data-quarto-table-cell-role="th">Australia/ACT/Canberra/Holiday</th> +<th data-quarto-table-cell-role="th">Australia/ACT/Canberra/Other</th> +<th data-quarto-table-cell-role="th">Australia/ACT/Canberra/Visiting</th> +<th data-quarto-table-cell-role="th">Australia/New South Wales/Blue Mountains/Business</th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td data-quarto-table-cell-role="th">Australia</td> +<td>1.0</td> +<td>1.0</td> +<td>1.0</td> +<td>1.0</td> +<td>1.0</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">Australia/ACT</td> +<td>1.0</td> +<td>1.0</td> +<td>1.0</td> +<td>1.0</td> +<td>0.0</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">Australia/New South Wales</td> +<td>0.0</td> +<td>0.0</td> +<td>0.0</td> +<td>0.0</td> +<td>1.0</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">Australia/Northern Territory</td> +<td>0.0</td> +<td>0.0</td> +<td>0.0</td> +<td>0.0</td> +<td>0.0</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">Australia/Queensland</td> +<td>0.0</td> +<td>0.0</td> +<td>0.0</td> +<td>0.0</td> +<td>0.0</td> +</tr> +</tbody> +</table> + +</div> +</div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb10"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a>tags[<span class="st">'Country/Purpose'</span>]</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<pre><code>array(['Australia/Business', 'Australia/Holiday', 'Australia/Other', + 'Australia/Visiting'], dtype=object)</code></pre> +</div> +</div> +<p>We can visualize the <code>S_df</code> dataframe and <code>Y_df</code> using the <a href="https://Nixtla.github.io/hierarchicalforecast/utils.html#hierarchicalplot"><code>HierarchicalPlot</code></a> class as follows.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb12"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a>hplot <span class="op">=</span> HierarchicalPlot(S<span class="op">=</span>S_df, tags<span class="op">=</span>tags)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb13"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a>hplot.plot_summing_matrix()</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<p><img src="AustralianDomesticTourism-Bootstraped-Intervals_files/figure-html/cell-11-output-1.png" class="img-fluid"></p> +</div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb14"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a>hplot.plot_hierarchically_linked_series(</span> +<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a> bottom_series<span class="op">=</span><span class="st">'Australia/ACT/Canberra/Holiday'</span>,</span> +<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a> Y_df<span class="op">=</span>Y_df.set_index(<span class="st">'unique_id'</span>)</span> +<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<p><img src="AustralianDomesticTourism-Bootstraped-Intervals_files/figure-html/cell-12-output-1.png" class="img-fluid"></p> +</div> +</div> +<section id="split-traintest-sets" class="level3"> +<h3 class="anchored" data-anchor-id="split-traintest-sets">Split Train/Test sets</h3> +<p>We use the final two years (8 quarters) as test set.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb15"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a>Y_test_df <span class="op">=</span> Y_df.groupby(<span class="st">'unique_id'</span>).tail(<span class="dv">8</span>)</span> +<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a>Y_train_df <span class="op">=</span> Y_df.drop(Y_test_df.index)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb16"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a>Y_test_df <span class="op">=</span> Y_test_df.set_index(<span class="st">'unique_id'</span>)</span> +<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a>Y_train_df <span class="op">=</span> Y_train_df.set_index(<span class="st">'unique_id'</span>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb17"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a>Y_train_df.groupby(<span class="st">'unique_id'</span>).size()</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<pre><code>unique_id +Australia 72 +Australia/ACT 72 +Australia/ACT/Business 72 +Australia/ACT/Canberra 72 +Australia/ACT/Canberra/Business 72 + .. +Australia/Western Australia/Experience Perth/Other 72 +Australia/Western Australia/Experience Perth/Visiting 72 +Australia/Western Australia/Holiday 72 +Australia/Western Australia/Other 72 +Australia/Western Australia/Visiting 72 +Length: 425, dtype: int64</code></pre> +</div> +</div> +</section> +</section> +<section id="computing-base-forecasts" class="level2"> +<h2 class="anchored" data-anchor-id="computing-base-forecasts">Computing Base Forecasts</h2> +<p>The following cell computes the <strong>base forecasts</strong> for each time series in <code>Y_df</code> using the <code>AutoETS</code> and model. Observe that <code>Y_hat_df</code> contains the forecasts but they are not coherent. Since we are computing prediction intervals using bootstrapping, we only need the fitted values of the models.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb19"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a>fcst <span class="op">=</span> StatsForecast(df<span class="op">=</span>Y_train_df, </span> +<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a> models<span class="op">=</span>[ETS(season_length<span class="op">=</span><span class="dv">4</span>, model<span class="op">=</span><span class="st">'ZAA'</span>)],</span> +<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a> freq<span class="op">=</span><span class="st">'QS'</span>, n_jobs<span class="op">=-</span><span class="dv">1</span>)</span> +<span id="cb19-4"><a href="#cb19-4" aria-hidden="true" tabindex="-1"></a>Y_hat_df <span class="op">=</span> fcst.forecast(h<span class="op">=</span><span class="dv">8</span>, fitted<span class="op">=</span><span class="va">True</span>)</span> +<span id="cb19-5"><a href="#cb19-5" aria-hidden="true" tabindex="-1"></a>Y_fitted_df <span class="op">=</span> fcst.forecast_fitted_values()</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-stderr"> +<pre><code>/Users/fedex/miniconda3/envs/hierarchicalforecast/lib/python3.10/site-packages/statsforecast/models.py:526: FutureWarning: `ETS` will be deprecated in future versions of `StatsForecast`. Please use `AutoETS` instead. + ETS._warn()</code></pre> +</div> +</div> +</section> +<section id="reconcile-base-forecasts" class="level2"> +<h2 class="anchored" data-anchor-id="reconcile-base-forecasts">Reconcile Base Forecasts</h2> +<p>The following cell makes the previous forecasts coherent using the <a href="https://Nixtla.github.io/hierarchicalforecast/core.html#hierarchicalreconciliation"><code>HierarchicalReconciliation</code></a> class. Since the hierarchy structure is not strict, we canāt use methods such as <a href="https://Nixtla.github.io/hierarchicalforecast/methods.html#topdown"><code>TopDown</code></a> or <a href="https://Nixtla.github.io/hierarchicalforecast/methods.html#middleout"><code>MiddleOut</code></a>. In this example we use <a href="https://Nixtla.github.io/hierarchicalforecast/methods.html#bottomup"><code>BottomUp</code></a> and <a href="https://Nixtla.github.io/hierarchicalforecast/methods.html#mintrace"><code>MinTrace</code></a>. If you want to calculate prediction intervals, you have to use the <code>level</code> argument as follows and set <code>intervals_method='bootstrap'</code>.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb21"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb21-1"><a href="#cb21-1" aria-hidden="true" tabindex="-1"></a>reconcilers <span class="op">=</span> [</span> +<span id="cb21-2"><a href="#cb21-2" aria-hidden="true" tabindex="-1"></a> BottomUp(),</span> +<span id="cb21-3"><a href="#cb21-3" aria-hidden="true" tabindex="-1"></a> MinTrace(method<span class="op">=</span><span class="st">'mint_shrink'</span>),</span> +<span id="cb21-4"><a href="#cb21-4" aria-hidden="true" tabindex="-1"></a> MinTrace(method<span class="op">=</span><span class="st">'ols'</span>)</span> +<span id="cb21-5"><a href="#cb21-5" aria-hidden="true" tabindex="-1"></a>]</span> +<span id="cb21-6"><a href="#cb21-6" aria-hidden="true" tabindex="-1"></a>hrec <span class="op">=</span> HierarchicalReconciliation(reconcilers<span class="op">=</span>reconcilers)</span> +<span id="cb21-7"><a href="#cb21-7" aria-hidden="true" tabindex="-1"></a>Y_rec_df <span class="op">=</span> hrec.reconcile(Y_hat_df<span class="op">=</span>Y_hat_df, Y_df<span class="op">=</span>Y_fitted_df, S<span class="op">=</span>S_df, </span> +<span id="cb21-8"><a href="#cb21-8" aria-hidden="true" tabindex="-1"></a> tags<span class="op">=</span>tags, level<span class="op">=</span>[<span class="dv">80</span>, <span class="dv">90</span>], </span> +<span id="cb21-9"><a href="#cb21-9" aria-hidden="true" tabindex="-1"></a> intervals_method<span class="op">=</span><span class="st">'bootstrap'</span>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<p>The dataframe <code>Y_rec_df</code> contains the reconciled forecasts.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb22"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb22-1"><a href="#cb22-1" aria-hidden="true" tabindex="-1"></a>Y_rec_df.head()</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<div> + + +<table class="dataframe table table-sm table-striped small" data-quarto-postprocess="true" data-border="1"> +<thead> +<tr class="header"> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th">ds</th> +<th data-quarto-table-cell-role="th">ETS</th> +<th data-quarto-table-cell-role="th">ETS/BottomUp</th> +<th data-quarto-table-cell-role="th">ETS/BottomUp-lo-90</th> +<th data-quarto-table-cell-role="th">ETS/BottomUp-lo-80</th> +<th data-quarto-table-cell-role="th">ETS/BottomUp-hi-80</th> +<th data-quarto-table-cell-role="th">ETS/BottomUp-hi-90</th> +<th data-quarto-table-cell-role="th">ETS/MinTrace_method-mint_shrink</th> +<th data-quarto-table-cell-role="th">ETS/MinTrace_method-mint_shrink-lo-90</th> +<th data-quarto-table-cell-role="th">ETS/MinTrace_method-mint_shrink-lo-80</th> +<th data-quarto-table-cell-role="th">ETS/MinTrace_method-mint_shrink-hi-80</th> +<th data-quarto-table-cell-role="th">ETS/MinTrace_method-mint_shrink-hi-90</th> +<th data-quarto-table-cell-role="th">ETS/MinTrace_method-ols</th> +<th data-quarto-table-cell-role="th">ETS/MinTrace_method-ols-lo-90</th> +<th data-quarto-table-cell-role="th">ETS/MinTrace_method-ols-lo-80</th> +<th data-quarto-table-cell-role="th">ETS/MinTrace_method-ols-hi-80</th> +<th data-quarto-table-cell-role="th">ETS/MinTrace_method-ols-hi-90</th> +</tr> +<tr class="odd"> +<th data-quarto-table-cell-role="th">unique_id</th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td data-quarto-table-cell-role="th">Australia</td> +<td>2016-01-01</td> +<td>26080.878906</td> +<td>24487.349609</td> +<td>23244.120996</td> +<td>23333.694727</td> +<td>25381.792969</td> +<td>25426.333984</td> +<td>25532.523559</td> +<td>24428.911701</td> +<td>24709.210638</td> +<td>26365.606934</td> +<td>26476.255501</td> +<td>26034.114241</td> +<td>24914.136375</td> +<td>25100.462938</td> +<td>27102.735022</td> +<td>27176.416922</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">Australia</td> +<td>2016-04-01</td> +<td>24587.011719</td> +<td>23069.744141</td> +<td>21826.519434</td> +<td>21912.962891</td> +<td>23946.606250</td> +<td>24281.447266</td> +<td>24118.557177</td> +<td>23199.968626</td> +<td>23295.244252</td> +<td>25108.470410</td> +<td>25489.383606</td> +<td>24567.460995</td> +<td>23484.050568</td> +<td>23640.638423</td> +<td>25709.763678</td> +<td>25809.249492</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">Australia</td> +<td>2016-07-01</td> +<td>24147.308594</td> +<td>22689.777344</td> +<td>21297.136719</td> +<td>21530.438281</td> +<td>23701.173828</td> +<td>24155.820312</td> +<td>23731.251387</td> +<td>22627.639669</td> +<td>22818.729182</td> +<td>24821.488458</td> +<td>25246.867432</td> +<td>24150.134898</td> +<td>23030.156834</td> +<td>23155.025556</td> +<td>25359.992376</td> +<td>25404.841402</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">Australia</td> +<td>2016-10-01</td> +<td>24794.041016</td> +<td>23429.757812</td> +<td>22037.123047</td> +<td>22276.453125</td> +<td>24241.417969</td> +<td>24441.160156</td> +<td>24486.549344</td> +<td>23385.927232</td> +<td>23600.704525</td> +<td>25353.555625</td> +<td>25481.478557</td> +<td>24831.584516</td> +<td>23725.924464</td> +<td>23836.475174</td> +<td>25900.205254</td> +<td>25977.265089</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">Australia</td> +<td>2017-01-01</td> +<td>26284.000000</td> +<td>24940.042969</td> +<td>23696.722754</td> +<td>23904.382812</td> +<td>25814.941406</td> +<td>25974.169922</td> +<td>26041.867488</td> +<td>24972.077858</td> +<td>25158.986710</td> +<td>26918.104747</td> +<td>27135.580845</td> +<td>26348.203335</td> +<td>25254.659324</td> +<td>25487.502291</td> +<td>27410.873035</td> +<td>27477.334507</td> +</tr> +</tbody> +</table> + +</div> +</div> +</div> +</section> +<section id="plot-predictions" class="level2"> +<h2 class="anchored" data-anchor-id="plot-predictions">Plot Predictions</h2> +<p>Then we can plot the probabilist forecasts using the following function.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb23"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb23-1"><a href="#cb23-1" aria-hidden="true" tabindex="-1"></a>plot_df <span class="op">=</span> pd.concat([Y_df.set_index([<span class="st">'unique_id'</span>, <span class="st">'ds'</span>]), </span> +<span id="cb23-2"><a href="#cb23-2" aria-hidden="true" tabindex="-1"></a> Y_rec_df.set_index(<span class="st">'ds'</span>, append<span class="op">=</span><span class="va">True</span>)], axis<span class="op">=</span><span class="dv">1</span>)</span> +<span id="cb23-3"><a href="#cb23-3" aria-hidden="true" tabindex="-1"></a>plot_df <span class="op">=</span> plot_df.reset_index(<span class="st">'ds'</span>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<section id="plot-single-time-series" class="level3"> +<h3 class="anchored" data-anchor-id="plot-single-time-series">Plot single time series</h3> +<div class="cell"> +<div class="sourceCode cell-code" id="cb24"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb24-1"><a href="#cb24-1" aria-hidden="true" tabindex="-1"></a>hplot.plot_series(</span> +<span id="cb24-2"><a href="#cb24-2" aria-hidden="true" tabindex="-1"></a> series<span class="op">=</span><span class="st">'Australia'</span>,</span> +<span id="cb24-3"><a href="#cb24-3" aria-hidden="true" tabindex="-1"></a> Y_df<span class="op">=</span>plot_df, </span> +<span id="cb24-4"><a href="#cb24-4" aria-hidden="true" tabindex="-1"></a> models<span class="op">=</span>[<span class="st">'y'</span>, <span class="st">'ETS'</span>, <span class="st">'ETS/MinTrace_method-ols'</span>, <span class="st">'ETS/MinTrace_method-mint_shrink'</span>],</span> +<span id="cb24-5"><a href="#cb24-5" aria-hidden="true" tabindex="-1"></a> level<span class="op">=</span>[<span class="dv">80</span>]</span> +<span id="cb24-6"><a href="#cb24-6" aria-hidden="true" tabindex="-1"></a>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<p><img src="AustralianDomesticTourism-Bootstraped-Intervals_files/figure-html/cell-20-output-1.png" class="img-fluid"></p> +</div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb25"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb25-1"><a href="#cb25-1" aria-hidden="true" tabindex="-1"></a><span class="co"># Since we are plotting a bottom time series</span></span> +<span id="cb25-2"><a href="#cb25-2" aria-hidden="true" tabindex="-1"></a><span class="co"># the probabilistic and mean forecasts</span></span> +<span id="cb25-3"><a href="#cb25-3" aria-hidden="true" tabindex="-1"></a><span class="co"># differ due to bootstrapping</span></span> +<span id="cb25-4"><a href="#cb25-4" aria-hidden="true" tabindex="-1"></a>hplot.plot_series(</span> +<span id="cb25-5"><a href="#cb25-5" aria-hidden="true" tabindex="-1"></a> series<span class="op">=</span><span class="st">'Australia/Western Australia/Experience Perth/Visiting'</span>,</span> +<span id="cb25-6"><a href="#cb25-6" aria-hidden="true" tabindex="-1"></a> Y_df<span class="op">=</span>plot_df, </span> +<span id="cb25-7"><a href="#cb25-7" aria-hidden="true" tabindex="-1"></a> models<span class="op">=</span>[<span class="st">'y'</span>, <span class="st">'ETS'</span>, <span class="st">'ETS/BottomUp'</span>],</span> +<span id="cb25-8"><a href="#cb25-8" aria-hidden="true" tabindex="-1"></a> level<span class="op">=</span>[<span class="dv">80</span>]</span> +<span id="cb25-9"><a href="#cb25-9" aria-hidden="true" tabindex="-1"></a>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<p><img src="AustralianDomesticTourism-Bootstraped-Intervals_files/figure-html/cell-21-output-1.png" class="img-fluid"></p> +</div> +</div> +</section> +<section id="plot-hierarchichally-linked-time-series" class="level3"> +<h3 class="anchored" data-anchor-id="plot-hierarchichally-linked-time-series">Plot hierarchichally linked time series</h3> +<div class="cell"> +<div class="sourceCode cell-code" id="cb26"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb26-1"><a href="#cb26-1" aria-hidden="true" tabindex="-1"></a>hplot.plot_hierarchically_linked_series(</span> +<span id="cb26-2"><a href="#cb26-2" aria-hidden="true" tabindex="-1"></a> bottom_series<span class="op">=</span><span class="st">'Australia/Western Australia/Experience Perth/Visiting'</span>,</span> +<span id="cb26-3"><a href="#cb26-3" aria-hidden="true" tabindex="-1"></a> Y_df<span class="op">=</span>plot_df, </span> +<span id="cb26-4"><a href="#cb26-4" aria-hidden="true" tabindex="-1"></a> models<span class="op">=</span>[<span class="st">'y'</span>, <span class="st">'ETS'</span>, <span class="st">'ETS/MinTrace_method-ols'</span>, <span class="st">'ETS/BottomUp'</span>],</span> +<span id="cb26-5"><a href="#cb26-5" aria-hidden="true" tabindex="-1"></a> level<span class="op">=</span>[<span class="dv">80</span>]</span> +<span id="cb26-6"><a href="#cb26-6" aria-hidden="true" tabindex="-1"></a>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<p><img src="AustralianDomesticTourism-Bootstraped-Intervals_files/figure-html/cell-22-output-1.png" class="img-fluid"></p> +</div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb27"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb27-1"><a href="#cb27-1" aria-hidden="true" tabindex="-1"></a><span class="co"># ACT only has Canberra</span></span> +<span id="cb27-2"><a href="#cb27-2" aria-hidden="true" tabindex="-1"></a>hplot.plot_hierarchically_linked_series(</span> +<span id="cb27-3"><a href="#cb27-3" aria-hidden="true" tabindex="-1"></a> bottom_series<span class="op">=</span><span class="st">'Australia/ACT/Canberra/Other'</span>,</span> +<span id="cb27-4"><a href="#cb27-4" aria-hidden="true" tabindex="-1"></a> Y_df<span class="op">=</span>plot_df, </span> +<span id="cb27-5"><a href="#cb27-5" aria-hidden="true" tabindex="-1"></a> models<span class="op">=</span>[<span class="st">'y'</span>, <span class="st">'ETS/MinTrace_method-mint_shrink'</span>],</span> +<span id="cb27-6"><a href="#cb27-6" aria-hidden="true" tabindex="-1"></a> level<span class="op">=</span>[<span class="dv">80</span>, <span class="dv">90</span>]</span> +<span id="cb27-7"><a href="#cb27-7" aria-hidden="true" tabindex="-1"></a>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<p><img src="AustralianDomesticTourism-Bootstraped-Intervals_files/figure-html/cell-23-output-1.png" class="img-fluid"></p> +</div> +</div> +</section> +<section id="references" class="level3"> +<h3 class="anchored" data-anchor-id="references">References</h3> +<ul> +<li><a href="https://otexts.com/fpp3/hierarchical.html">Hyndman, R.J., & Athanasopoulos, G. (2021). āForecasting: principles and practice, 3rd edition: Chapter 11: Forecasting hierarchical and grouped series.ā. OTexts: Melbourne, Australia. OTexts.com/fpp3 Accessed on July 2022.</a></li> +<li><a href="https://robjhyndman.com/publications/mint/">Shanika L. Wickramasuriya, George Athanasopoulos, and Rob J. Hyndman. Optimal forecast reconciliation for hierarchical and grouped time series through trace minimization.Journal of the American Statistical Association, 114(526):804ā819, 2019. doi: 10.1080/01621459.2018.1448825. URL https://robjhyndman.com/publications/mint/.</a></li> +<li><a href="https://bridges.monash.edu/articles/thesis/Probabilistic_Forecast_Reconciliation_Theory_and_Applications/11869533">Puwasala Gamakumara Ph. D. dissertation. Monash University, Econometrics and Business Statistics (2020). āProbabilistic Forecast Reconciliationā</a></li> +</ul> + + +</section> +</section> + +<p>If you find the code useful, please ā us on <a href="https://github.com/nixtla/hierarchicalforecast">Github</a></p></main> <!-- /main --> +<script id="quarto-html-after-body" type="application/javascript"> +window.document.addEventListener("DOMContentLoaded", function (event) { + const toggleBodyColorMode = (bsSheetEl) => { + const mode = bsSheetEl.getAttribute("data-mode"); + const bodyEl = window.document.querySelector("body"); + if (mode === "dark") { + bodyEl.classList.add("quarto-dark"); + bodyEl.classList.remove("quarto-light"); + } else { + bodyEl.classList.add("quarto-light"); + bodyEl.classList.remove("quarto-dark"); + } + } + const toggleBodyColorPrimary = () => { + const bsSheetEl = window.document.querySelector("link#quarto-bootstrap"); + if (bsSheetEl) { + toggleBodyColorMode(bsSheetEl); + } + } + toggleBodyColorPrimary(); + const icon = "ī§"; + const anchorJS = new window.AnchorJS(); + anchorJS.options = { + placement: 'right', + icon: icon + }; + anchorJS.add('.anchored'); + const isCodeAnnotation = (el) => { + for (const clz of el.classList) { + if (clz.startsWith('code-annotation-')) { + return true; + } + } + return false; + } + const clipboard = new window.ClipboardJS('.code-copy-button', { + text: function(trigger) { + const codeEl = trigger.previousElementSibling.cloneNode(true); + for (const childEl of codeEl.children) { + if (isCodeAnnotation(childEl)) { + childEl.remove(); + } + } + return codeEl.innerText; + } + }); + clipboard.on('success', function(e) { + // button target + const button = e.trigger; + // don't keep focus + button.blur(); + // flash "checked" + button.classList.add('code-copy-button-checked'); + var currentTitle = button.getAttribute("title"); + button.setAttribute("title", "Copied!"); + let tooltip; + if (window.bootstrap) { + button.setAttribute("data-bs-toggle", "tooltip"); + button.setAttribute("data-bs-placement", "left"); + button.setAttribute("data-bs-title", "Copied!"); + tooltip = new bootstrap.Tooltip(button, + { trigger: "manual", + customClass: "code-copy-button-tooltip", + offset: [0, -8]}); + tooltip.show(); + } + setTimeout(function() { + if (tooltip) { + tooltip.hide(); + button.removeAttribute("data-bs-title"); + button.removeAttribute("data-bs-toggle"); + button.removeAttribute("data-bs-placement"); + } + button.setAttribute("title", currentTitle); + button.classList.remove('code-copy-button-checked'); + }, 1000); + // clear code selection + e.clearSelection(); + }); + function tippyHover(el, contentFn) { + const config = { + allowHTML: true, + content: contentFn, + maxWidth: 500, + delay: 100, + arrow: false, + appendTo: function(el) { + return el.parentElement; + }, + interactive: true, + interactiveBorder: 10, + theme: 'quarto', + placement: 'bottom-start' + }; + window.tippy(el, config); + } + const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]'); + for (var i=0; i<noterefs.length; i++) { + const ref = noterefs[i]; + tippyHover(ref, function() { + // use id or data attribute instead here + let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href'); + try { href = new URL(href).hash; } catch {} + const id = href.replace(/^#\/?/, ""); + const note = window.document.getElementById(id); + return note.innerHTML; + }); + } + let selectedAnnoteEl; + const selectorForAnnotation = ( cell, annotation) => { + let cellAttr = 'data-code-cell="' + cell + '"'; + let lineAttr = 'data-code-annotation="' + annotation + '"'; + const selector = 'span[' + cellAttr + '][' + lineAttr + ']'; + return selector; + } + const selectCodeLines = (annoteEl) => { + const doc = window.document; + const targetCell = annoteEl.getAttribute("data-target-cell"); + const targetAnnotation = annoteEl.getAttribute("data-target-annotation"); + const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation)); + const lines = annoteSpan.getAttribute("data-code-lines").split(","); + const lineIds = lines.map((line) => { + return targetCell + "-" + line; + }) + let top = null; + let height = null; + let parent = null; + if (lineIds.length > 0) { + //compute the position of the single el (top and bottom and make a div) + const el = window.document.getElementById(lineIds[0]); + top = el.offsetTop; + height = el.offsetHeight; + parent = el.parentElement.parentElement; + if (lineIds.length > 1) { + const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]); + const bottom = lastEl.offsetTop + lastEl.offsetHeight; + height = bottom - top; + } + if (top !== null && height !== null && parent !== null) { + // cook up a div (if necessary) and position it + let div = window.document.getElementById("code-annotation-line-highlight"); + if (div === null) { + div = window.document.createElement("div"); + div.setAttribute("id", "code-annotation-line-highlight"); + div.style.position = 'absolute'; + parent.appendChild(div); + } + div.style.top = top - 2 + "px"; + div.style.height = height + 4 + "px"; + let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter"); + if (gutterDiv === null) { + gutterDiv = window.document.createElement("div"); + gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter"); + gutterDiv.style.position = 'absolute'; + const codeCell = window.document.getElementById(targetCell); + const gutter = codeCell.querySelector('.code-annotation-gutter'); + gutter.appendChild(gutterDiv); + } + gutterDiv.style.top = top - 2 + "px"; + gutterDiv.style.height = height + 4 + "px"; + } + selectedAnnoteEl = annoteEl; + } + }; + const unselectCodeLines = () => { + const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"]; + elementsIds.forEach((elId) => { + const div = window.document.getElementById(elId); + if (div) { + div.remove(); + } + }); + selectedAnnoteEl = undefined; + }; + // Attach click handler to the DT + const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); + for (const annoteDlNode of annoteDls) { + annoteDlNode.addEventListener('click', (event) => { + const clickedEl = event.target; + if (clickedEl !== selectedAnnoteEl) { + unselectCodeLines(); + const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active'); + if (activeEl) { + activeEl.classList.remove('code-annotation-active'); + } + selectCodeLines(clickedEl); + clickedEl.classList.add('code-annotation-active'); + } else { + // Unselect the line + unselectCodeLines(); + clickedEl.classList.remove('code-annotation-active'); + } + }); + } + const findCites = (el) => { + const parentEl = el.parentElement; + if (parentEl) { + const cites = parentEl.dataset.cites; + if (cites) { + return { + el, + cites: cites.split(' ') + }; + } else { + return findCites(el.parentElement) + } + } else { + return undefined; + } + }; + var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]'); + for (var i=0; i<bibliorefs.length; i++) { + const ref = bibliorefs[i]; + const citeInfo = findCites(ref); + if (citeInfo) { + tippyHover(citeInfo.el, function() { + var popup = window.document.createElement('div'); + citeInfo.cites.forEach(function(cite) { + var citeDiv = window.document.createElement('div'); + citeDiv.classList.add('hanging-indent'); + citeDiv.classList.add('csl-entry'); + var biblioDiv = window.document.getElementById('ref-' + cite); + if (biblioDiv) { + citeDiv.innerHTML = biblioDiv.innerHTML; + } + popup.appendChild(citeDiv); + }); + return popup.innerHTML; + }); + } + } +}); +</script> +</div> <!-- /content --> + + + +</body></html> \ No newline at end of file diff --git a/examples/australiandomestictourism-intervals.html b/examples/australiandomestictourism-intervals.html new file mode 100644 index 00000000..e441fcb7 --- /dev/null +++ b/examples/australiandomestictourism-intervals.html @@ -0,0 +1,1272 @@ +<!DOCTYPE html> +<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head> + +<meta charset="utf-8"> +<meta name="generator" content="quarto-1.3.450"> + +<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes"> + + +<title>hierarchicalforecast - Normality</title> +<style> +code{white-space: pre-wrap;} +span.smallcaps{font-variant: small-caps;} +div.columns{display: flex; gap: min(4vw, 1.5em);} +div.column{flex: auto; overflow-x: auto;} +div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;} +ul.task-list{list-style: none;} +ul.task-list li input[type="checkbox"] { + width: 0.8em; + margin: 0 0.8em 0.2em -1em; /* quarto-specific, see https://github.com/quarto-dev/quarto-cli/issues/4556 */ + vertical-align: middle; +} +/* CSS for syntax highlighting */ +pre > code.sourceCode { white-space: pre; position: relative; } +pre > code.sourceCode > span { display: inline-block; line-height: 1.25; } +pre > code.sourceCode > span:empty { height: 1.2em; } +.sourceCode { overflow: visible; } +code.sourceCode > span { color: inherit; text-decoration: inherit; } +div.sourceCode { margin: 1em 0; } +pre.sourceCode { margin: 0; } +@media screen { +div.sourceCode { overflow: auto; } +} +@media print { +pre > code.sourceCode { white-space: pre-wrap; } +pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; } +} +pre.numberSource code + { counter-reset: source-line 0; } +pre.numberSource code > span + { position: relative; left: -4em; counter-increment: source-line; } +pre.numberSource code > span > a:first-child::before + { content: counter(source-line); + position: relative; left: -1em; text-align: right; vertical-align: baseline; + border: none; display: inline-block; + -webkit-touch-callout: none; -webkit-user-select: none; + -khtml-user-select: none; -moz-user-select: none; + -ms-user-select: none; user-select: none; + padding: 0 4px; width: 4em; + } +pre.numberSource { margin-left: 3em; padding-left: 4px; } +div.sourceCode + { } +@media screen { +pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; } +} +</style> + + +<script src="../site_libs/quarto-nav/quarto-nav.js"></script> +<script src="../site_libs/quarto-nav/headroom.min.js"></script> +<script src="../site_libs/clipboard/clipboard.min.js"></script> +<script src="../site_libs/quarto-search/autocomplete.umd.js"></script> +<script src="../site_libs/quarto-search/fuse.min.js"></script> +<script src="../site_libs/quarto-search/quarto-search.js"></script> +<meta name="quarto:offset" content="../"> +<link href="../favicon_png.png" rel="icon" type="image/png"> +<script src="../site_libs/quarto-html/quarto.js"></script> +<script src="../site_libs/quarto-html/popper.min.js"></script> +<script src="../site_libs/quarto-html/tippy.umd.min.js"></script> +<script src="../site_libs/quarto-html/anchor.min.js"></script> +<link href="../site_libs/quarto-html/tippy.css" rel="stylesheet"> +<link href="../site_libs/quarto-html/quarto-syntax-highlighting.css" rel="stylesheet" id="quarto-text-highlighting-styles"> +<script src="../site_libs/bootstrap/bootstrap.min.js"></script> +<link href="../site_libs/bootstrap/bootstrap-icons.css" rel="stylesheet"> +<link href="../site_libs/bootstrap/bootstrap.min.css" rel="stylesheet" id="quarto-bootstrap" data-mode="light"> +<script id="quarto-search-options" type="application/json">{ + "location": "navbar", + "copy-button": false, + "collapse-after": 3, + "panel-placement": "end", + "type": "overlay", + "limit": 20, + "language": { + "search-no-results-text": "No results", + "search-matching-documents-text": "matching documents", + "search-copy-link-title": "Copy link to search", + "search-hide-matches-text": "Hide additional matches", + "search-more-match-text": "more match in this document", + "search-more-matches-text": "more matches in this document", + "search-clear-button-title": "Clear", + "search-detached-cancel-button-title": "Cancel", + "search-submit-button-title": "Submit", + "search-label": "Search" + } +}</script> +<script async="" src="https://www.googletagmanager.com/gtag/js?id=G-NXJNCVR18L"></script> + +<script type="text/javascript"> + +window.dataLayer = window.dataLayer || []; +function gtag(){dataLayer.push(arguments);} +gtag('js', new Date()); +gtag('config', 'G-NXJNCVR18L', { 'anonymize_ip': true}); +</script> +<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js" integrity="sha512-c3Nl8+7g4LMSTdrm621y7kf9v3SDPnhxLNhcjFJbKECVnmZHTdo+IRO05sNLTH/D3vA6u1X32ehoLC7WFVdheg==" crossorigin="anonymous"></script> +<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js" integrity="sha512-bLT0Qm9VnAYZDflyKcBaQ2gg0hSYNQrJ8RilYldYQ1FxQYoCLtUjuuRuZo+fjqhx/qtq/1itJ0C2ejDxltZVFg==" crossorigin="anonymous"></script> +<script type="application/javascript">define('jquery', [],function() {return window.jQuery;})</script> + + <script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script> + <script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml-full.js" type="text/javascript"></script> + +<link rel="stylesheet" href="../styles.css"> +<meta property="og:title" content="hierarchicalforecast - Normality"> +<meta property="og:description" content=""> +<meta property="og:image" content="https://colab.research.google.com/assets/colab-badge.svg"> +<meta property="og:site-name" content="hierarchicalforecast"> +<meta name="twitter:title" content="hierarchicalforecast - Normality"> +<meta name="twitter:description" content=""> +<meta name="twitter:image" content="https://colab.research.google.com/assets/colab-badge.svg"> +<meta name="twitter:card" content="summary_large_image"> +</head> + +<body class="nav-sidebar floating nav-fixed"> + +<div id="quarto-search-results"></div> + <header id="quarto-header" class="headroom fixed-top"> + <nav class="navbar navbar-expand-lg navbar-dark "> + <div class="navbar-container container-fluid"> + <div class="navbar-brand-container"> + <a class="navbar-brand" href="../index.html"> + <span class="navbar-title">hierarchicalforecast</span> + </a> + </div> + <div id="quarto-search" class="" title="Search"></div> + <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + <span class="navbar-toggler-icon"></span> +</button> + <div class="collapse navbar-collapse" id="navbarCollapse"> + <ul class="navbar-nav navbar-nav-scroll me-auto"> + <li class="nav-item"> + <a class="nav-link active" href="../examples/tourismsmall.html" rel="" target="" aria-current="page"> + <span class="menu-text">Get Started</span></a> + </li> + <li class="nav-item dropdown "> + <a class="nav-link dropdown-toggle" href="#" id="nav-menu-nixtlaverse" role="button" data-bs-toggle="dropdown" aria-expanded="false" rel="" target=""> + <span class="menu-text">NixtlaVerse</span> + </a> + <ul class="dropdown-menu" aria-labelledby="nav-menu-nixtlaverse"> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/mlforecast" rel="" target=""> + <span class="dropdown-text">MLForecast š¤</span></a> + </li> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/neuralforecast" rel="" target=""> + <span class="dropdown-text">NeuralForecast š§ </span></a> + </li> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/statsforecast" rel="" target=""> + <span class="dropdown-text">StatsForecast ā”ļø</span></a> + </li> + </ul> + </li> + <li class="nav-item dropdown "> + <a class="nav-link dropdown-toggle" href="#" id="nav-menu-help" role="button" data-bs-toggle="dropdown" aria-expanded="false" rel="" target=""> + <span class="menu-text">Help</span> + </a> + <ul class="dropdown-menu" aria-labelledby="nav-menu-help"> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/hierarchicalforecast/issues/new/choose" rel="" target=""><i class="bi bi-bug" role="img"> +</i> + <span class="dropdown-text">Report an Issue</span></a> + </li> + <li> + <a class="dropdown-item" href="https://join.slack.com/t/nixtlacommunity/shared_invite/zt-1kd5m5db7-7OOfy0xVNf1PcvCiAPWvPw" rel="" target=""><i class="bi bi-chat-right-text" role="img"> +</i> + <span class="dropdown-text">Join our Slack</span></a> + </li> + </ul> + </li> +</ul> + <ul class="navbar-nav navbar-nav-scroll ms-auto"> + <li class="nav-item compact"> + <a class="nav-link" href="https://github.com/nixtla/hierarchicalforecast" rel="" target=""><i class="bi bi-github" role="img"> +</i> + <span class="menu-text"></span></a> + </li> + <li class="nav-item compact"> + <a class="nav-link" href="https://twitter.com/nixtlainc" rel="" target=""><i class="bi bi-twitter" role="img" aria-label="Nixtla Twitter"> +</i> + <span class="menu-text"></span></a> + </li> +</ul> + <div class="quarto-navbar-tools"> +</div> + </div> <!-- /navcollapse --> + </div> <!-- /container-fluid --> + </nav> + <nav class="quarto-secondary-nav"> + <div class="container-fluid d-flex"> + <button type="button" class="quarto-btn-toggle btn" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + <i class="bi bi-layout-text-sidebar-reverse"></i> + </button> + <nav class="quarto-page-breadcrumbs" aria-label="breadcrumb"><ol class="breadcrumb"><li class="breadcrumb-item">Tutorials</li><li class="breadcrumb-item"><a href="../examples/australiandomestictourism-intervals.html">Probabilistic Reconciliation</a></li><li class="breadcrumb-item"><a href="../examples/australiandomestictourism-intervals.html">Normality</a></li></ol></nav> + <a class="flex-grow-1" role="button" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + </a> + </div> + </nav> +</header> +<!-- content --> +<div id="quarto-content" class="quarto-container page-columns page-rows-contents page-layout-article page-navbar"> +<!-- sidebar --> + <nav id="quarto-sidebar" class="sidebar collapse collapse-horizontal sidebar-navigation floating overflow-auto"> + <div class="sidebar-menu-container"> + <ul class="list-unstyled mt-1"> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../index.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Hierarchical Forecast š</span></a> + </div> +</li> + <li class="px-0"><hr class="sidebar-divider hi "></li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-1" aria-expanded="false"> + <span class="menu-text">Getting Started</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-1" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-1" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/installation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Install</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/tourismsmall.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Reconciliation Quick Start</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/introduction.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Introduction</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-2" aria-expanded="true"> + <span class="menu-text">Tutorials</span></a> + <a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-2" aria-expanded="true" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-2" class="collapse list-unstyled sidebar-section depth1 show"> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-3" aria-expanded="false"> + <span class="menu-text">Point Reconciliation</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-3" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-3" class="collapse list-unstyled sidebar-section depth2 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Geographical Aggregation (Tourism)</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australianprisonpopulation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Geographical Aggregation (Prison Population)</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/nonnegativereconciliation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Non-Negative MinTrace</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-4" aria-expanded="true"> + <span class="menu-text">Probabilistic Reconciliation</span></a> + <a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-4" aria-expanded="true" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-4" class="collapse list-unstyled sidebar-section depth2 show"> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism-intervals.html" class="sidebar-item-text sidebar-link active"> + <span class="menu-text">Normality</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism-bootstraped-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Bootstrap</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism-permbu-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">PERMBU</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/tourismlarge-evaluation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Probabilistic Forecast Evaluation</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-5" aria-expanded="false"> + <span class="menu-text">ML Forecast Reconciliation</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-5" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-5" class="collapse list-unstyled sidebar-section depth2 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/hierarchicalforecast-gluonts.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">GluonTS</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/mlframeworksexample.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Neural/MLForecast</span></a> + </div> +</li> + </ul> + </li> + </ul> + </li> + <li class="sidebar-item"> + <span class="menu-text">Methods</span> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-6" aria-expanded="false"> + <span class="menu-text">API Reference</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-6" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-6" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../core.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Core </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../methods.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Reconciliation Methods </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../probabilistic_methods.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Probabilistic Methods </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../evaluation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Hierarchical Evaluation</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../utils.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Aggregation/Visualization Utils</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-7" aria-expanded="false"> + <span class="menu-text">Community</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-7" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-7" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item"> + <span class="menu-text">Contributing</span> + </li> + </ul> + </li> + </ul> + </div> +</nav> +<div id="quarto-sidebar-glass" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass"></div> +<!-- margin-sidebar --> + <div id="quarto-margin-sidebar" class="sidebar margin-sidebar"> + <nav id="TOC" role="doc-toc" class="toc-active"> + <h2 id="toc-title">On this page</h2> + + <ul> + <li><a href="#aggregate-bottom-time-series" id="toc-aggregate-bottom-time-series" class="nav-link active" data-scroll-target="#aggregate-bottom-time-series">Aggregate bottom time series</a> + <ul class="collapse"> + <li><a href="#split-traintest-sets" id="toc-split-traintest-sets" class="nav-link" data-scroll-target="#split-traintest-sets">Split Train/Test sets</a></li> + </ul></li> + <li><a href="#computing-base-forecasts" id="toc-computing-base-forecasts" class="nav-link" data-scroll-target="#computing-base-forecasts">Computing base forecasts</a></li> + <li><a href="#reconcile-forecasts" id="toc-reconcile-forecasts" class="nav-link" data-scroll-target="#reconcile-forecasts">Reconcile forecasts</a></li> + <li><a href="#plot-forecasts" id="toc-plot-forecasts" class="nav-link" data-scroll-target="#plot-forecasts">Plot forecasts</a> + <ul class="collapse"> + <li><a href="#plot-single-time-series" id="toc-plot-single-time-series" class="nav-link" data-scroll-target="#plot-single-time-series">Plot single time series</a></li> + <li><a href="#plot-hierarchichally-linked-time-series" id="toc-plot-hierarchichally-linked-time-series" class="nav-link" data-scroll-target="#plot-hierarchichally-linked-time-series">Plot hierarchichally linked time series</a></li> + <li><a href="#references" id="toc-references" class="nav-link" data-scroll-target="#references">References</a></li> + </ul></li> + </ul> +<div class="toc-actions"><div><i class="bi bi-github"></i></div><div class="action-links"><p><a href="https://github.com/Nixtla/hierarchicalforecast/issues/new" class="toc-action">Report an issue</a></p></div></div></nav> + </div> +<!-- main --> +<main class="content" id="quarto-document-content"> + +<header id="title-block-header" class="quarto-title-block default"> +<div class="quarto-title"> +<h1 class="title">Normality</h1> +</div> + + + +<div class="quarto-title-meta"> + + + + + </div> + + +</header> + +<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! --> +<p><a href="https://colab.research.google.com/github/Nixtla/hierarchicalforecast/blob/main/nbs/examples/AustralianDomesticTourism-Intervals.ipynb" target="_parent"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"></a></p> +<p>In many cases, only the time series at the lowest level of the hierarchies (bottom time series) are available. <code>HierarchicalForecast</code> has tools to create time series for all hierarchies and also allows you to calculate prediction intervals for all hierarchies. In this notebook we will see how to do it.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb1"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="op">!</span>pip install hierarchicalforecast statsforecast</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb2"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> numpy <span class="im">as</span> np</span> +<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> pandas <span class="im">as</span> pd</span> +<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> matplotlib.pyplot <span class="im">as</span> plt</span> +<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a><span class="co"># compute base forecast no coherent</span></span> +<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> statsforecast.models <span class="im">import</span> AutoARIMA</span> +<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> statsforecast.core <span class="im">import</span> StatsForecast</span> +<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a><span class="co">#obtain hierarchical reconciliation methods and evaluation</span></span> +<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> hierarchicalforecast.methods <span class="im">import</span> BottomUp, MinTrace</span> +<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> hierarchicalforecast.utils <span class="im">import</span> aggregate, HierarchicalPlot</span> +<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> hierarchicalforecast.core <span class="im">import</span> HierarchicalReconciliation</span> +<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> hierarchicalforecast.evaluation <span class="im">import</span> HierarchicalEvaluation</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-stderr"> +<pre><code>/Users/fedex/miniconda3/envs/hierarchicalforecast/lib/python3.10/site-packages/statsforecast/core.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html + from tqdm.autonotebook import tqdm</code></pre> +</div> +</div> +<section id="aggregate-bottom-time-series" class="level2"> +<h2 class="anchored" data-anchor-id="aggregate-bottom-time-series">Aggregate bottom time series</h2> +<p>In this example we will use the <a href="https://otexts.com/fpp3/tourism.html">Tourism</a> dataset from the <a href="https://otexts.com/fpp3/">Forecasting: Principles and Practice</a> book. The dataset only contains the time series at the lowest level, so we need to create the time series for all hierarchies.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb4"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a>Y_df <span class="op">=</span> pd.read_csv(<span class="st">'https://raw.githubusercontent.com/Nixtla/transfer-learning-time-series/main/datasets/tourism.csv'</span>)</span> +<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>Y_df <span class="op">=</span> Y_df.rename({<span class="st">'Trips'</span>: <span class="st">'y'</span>, <span class="st">'Quarter'</span>: <span class="st">'ds'</span>}, axis<span class="op">=</span><span class="dv">1</span>)</span> +<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>Y_df.insert(<span class="dv">0</span>, <span class="st">'Country'</span>, <span class="st">'Australia'</span>)</span> +<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>Y_df <span class="op">=</span> Y_df[[<span class="st">'Country'</span>, <span class="st">'Region'</span>, <span class="st">'State'</span>, <span class="st">'Purpose'</span>, <span class="st">'ds'</span>, <span class="st">'y'</span>]]</span> +<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>Y_df[<span class="st">'ds'</span>] <span class="op">=</span> Y_df[<span class="st">'ds'</span>].<span class="bu">str</span>.replace(<span class="vs">r'(\d+) (Q\d)'</span>, <span class="vs">r'\1-\2'</span>, regex<span class="op">=</span><span class="va">True</span>)</span> +<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>Y_df[<span class="st">'ds'</span>] <span class="op">=</span> pd.to_datetime(Y_df[<span class="st">'ds'</span>])</span> +<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>Y_df.head()</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<div> + + +<table class="dataframe table table-sm table-striped small" data-quarto-postprocess="true" data-border="1"> +<thead> +<tr class="header"> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th">Country</th> +<th data-quarto-table-cell-role="th">Region</th> +<th data-quarto-table-cell-role="th">State</th> +<th data-quarto-table-cell-role="th">Purpose</th> +<th data-quarto-table-cell-role="th">ds</th> +<th data-quarto-table-cell-role="th">y</th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td data-quarto-table-cell-role="th">0</td> +<td>Australia</td> +<td>Adelaide</td> +<td>South Australia</td> +<td>Business</td> +<td>1998-01-01</td> +<td>135.077690</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">1</td> +<td>Australia</td> +<td>Adelaide</td> +<td>South Australia</td> +<td>Business</td> +<td>1998-04-01</td> +<td>109.987316</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">2</td> +<td>Australia</td> +<td>Adelaide</td> +<td>South Australia</td> +<td>Business</td> +<td>1998-07-01</td> +<td>166.034687</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">3</td> +<td>Australia</td> +<td>Adelaide</td> +<td>South Australia</td> +<td>Business</td> +<td>1998-10-01</td> +<td>127.160464</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">4</td> +<td>Australia</td> +<td>Adelaide</td> +<td>South Australia</td> +<td>Business</td> +<td>1999-01-01</td> +<td>137.448533</td> +</tr> +</tbody> +</table> + +</div> +</div> +</div> +<p>The dataset can be grouped in the following non-strictly hierarchical structure.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb5"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a>spec <span class="op">=</span> [</span> +<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a> [<span class="st">'Country'</span>],</span> +<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a> [<span class="st">'Country'</span>, <span class="st">'State'</span>], </span> +<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a> [<span class="st">'Country'</span>, <span class="st">'Purpose'</span>], </span> +<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a> [<span class="st">'Country'</span>, <span class="st">'State'</span>, <span class="st">'Region'</span>], </span> +<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a> [<span class="st">'Country'</span>, <span class="st">'State'</span>, <span class="st">'Purpose'</span>], </span> +<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a> [<span class="st">'Country'</span>, <span class="st">'State'</span>, <span class="st">'Region'</span>, <span class="st">'Purpose'</span>]</span> +<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a>]</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<p>Using the <a href="https://Nixtla.github.io/hierarchicalforecast/utils.html#aggregate"><code>aggregate</code></a> function from <code>HierarchicalForecast</code> we can generate: 1. <code>Y_df</code>: the hierarchical structured series <span class="math inline">\(\mathbf{y}_{[a,b]\tau}\)</span> 2. <code>S_df</code>: the aggregation constraings dataframe with <span class="math inline">\(S_{[a,b]}\)</span> 3. <code>tags</code>: a list with the āunique_idsā conforming each aggregation level.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb6"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a>Y_df, S_df, tags <span class="op">=</span> aggregate(df<span class="op">=</span>Y_df, spec<span class="op">=</span>spec)</span> +<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>Y_df <span class="op">=</span> Y_df.reset_index()</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-stderr"> +<pre><code>/Users/fedex/miniconda3/envs/hierarchicalforecast/lib/python3.10/site-packages/sklearn/preprocessing/_encoders.py:828: FutureWarning: `sparse` was renamed to `sparse_output` in version 1.2 and will be removed in 1.4. `sparse_output` is ignored unless you leave `sparse` to its default value. + warnings.warn(</code></pre> +</div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb8"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a>Y_df.head()</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<div> + + +<table class="dataframe table table-sm table-striped small" data-quarto-postprocess="true" data-border="1"> +<thead> +<tr class="header"> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th">unique_id</th> +<th data-quarto-table-cell-role="th">ds</th> +<th data-quarto-table-cell-role="th">y</th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td data-quarto-table-cell-role="th">0</td> +<td>Australia</td> +<td>1998-01-01</td> +<td>23182.197269</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">1</td> +<td>Australia</td> +<td>1998-04-01</td> +<td>20323.380067</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">2</td> +<td>Australia</td> +<td>1998-07-01</td> +<td>19826.640511</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">3</td> +<td>Australia</td> +<td>1998-10-01</td> +<td>20830.129891</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">4</td> +<td>Australia</td> +<td>1999-01-01</td> +<td>22087.353380</td> +</tr> +</tbody> +</table> + +</div> +</div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb9"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a>S_df.iloc[:<span class="dv">5</span>, :<span class="dv">5</span>]</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<div> + + +<table class="dataframe table table-sm table-striped small" data-quarto-postprocess="true" data-border="1"> +<thead> +<tr class="header"> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th">Australia/ACT/Canberra/Business</th> +<th data-quarto-table-cell-role="th">Australia/ACT/Canberra/Holiday</th> +<th data-quarto-table-cell-role="th">Australia/ACT/Canberra/Other</th> +<th data-quarto-table-cell-role="th">Australia/ACT/Canberra/Visiting</th> +<th data-quarto-table-cell-role="th">Australia/New South Wales/Blue Mountains/Business</th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td data-quarto-table-cell-role="th">Australia</td> +<td>1.0</td> +<td>1.0</td> +<td>1.0</td> +<td>1.0</td> +<td>1.0</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">Australia/ACT</td> +<td>1.0</td> +<td>1.0</td> +<td>1.0</td> +<td>1.0</td> +<td>0.0</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">Australia/New South Wales</td> +<td>0.0</td> +<td>0.0</td> +<td>0.0</td> +<td>0.0</td> +<td>1.0</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">Australia/Northern Territory</td> +<td>0.0</td> +<td>0.0</td> +<td>0.0</td> +<td>0.0</td> +<td>0.0</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">Australia/Queensland</td> +<td>0.0</td> +<td>0.0</td> +<td>0.0</td> +<td>0.0</td> +<td>0.0</td> +</tr> +</tbody> +</table> + +</div> +</div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb10"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a>tags[<span class="st">'Country/Purpose'</span>]</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<pre><code>array(['Australia/Business', 'Australia/Holiday', 'Australia/Other', + 'Australia/Visiting'], dtype=object)</code></pre> +</div> +</div> +<p>We can visualize the <code>S</code> matrix and the data using the <a href="https://Nixtla.github.io/hierarchicalforecast/utils.html#hierarchicalplot"><code>HierarchicalPlot</code></a> class as follows.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb12"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a>hplot <span class="op">=</span> HierarchicalPlot(S<span class="op">=</span>S_df, tags<span class="op">=</span>tags)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb13"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a>hplot.plot_summing_matrix()</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<p><img src="AustralianDomesticTourism-Intervals_files/figure-html/cell-11-output-1.png" class="img-fluid"></p> +</div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb14"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a>hplot.plot_hierarchically_linked_series(</span> +<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a> bottom_series<span class="op">=</span><span class="st">'Australia/ACT/Canberra/Holiday'</span>,</span> +<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a> Y_df<span class="op">=</span>Y_df.set_index(<span class="st">'unique_id'</span>)</span> +<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<p><img src="AustralianDomesticTourism-Intervals_files/figure-html/cell-12-output-1.png" class="img-fluid"></p> +</div> +</div> +<section id="split-traintest-sets" class="level3"> +<h3 class="anchored" data-anchor-id="split-traintest-sets">Split Train/Test sets</h3> +<p>We use the final two years (8 quarters) as test set.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb15"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a>Y_test_df <span class="op">=</span> Y_df.groupby(<span class="st">'unique_id'</span>).tail(<span class="dv">8</span>)</span> +<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a>Y_train_df <span class="op">=</span> Y_df.drop(Y_test_df.index)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb16"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a>Y_test_df <span class="op">=</span> Y_test_df.set_index(<span class="st">'unique_id'</span>)</span> +<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a>Y_train_df <span class="op">=</span> Y_train_df.set_index(<span class="st">'unique_id'</span>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb17"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a>Y_train_df.groupby(<span class="st">'unique_id'</span>).size()</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<pre><code>unique_id +Australia 72 +Australia/ACT 72 +Australia/ACT/Business 72 +Australia/ACT/Canberra 72 +Australia/ACT/Canberra/Business 72 + .. +Australia/Western Australia/Experience Perth/Other 72 +Australia/Western Australia/Experience Perth/Visiting 72 +Australia/Western Australia/Holiday 72 +Australia/Western Australia/Other 72 +Australia/Western Australia/Visiting 72 +Length: 425, dtype: int64</code></pre> +</div> +</div> +</section> +</section> +<section id="computing-base-forecasts" class="level2"> +<h2 class="anchored" data-anchor-id="computing-base-forecasts">Computing base forecasts</h2> +<p>The following cell computes the <strong>base forecasts</strong> for each time series in <code>Y_df</code> using the <code>AutoARIMA</code> and model. Observe that <code>Y_hat_df</code> contains the forecasts but they are not coherent. To reconcile the prediction intervals we need to calculate the uncoherent intervals using the <code>level</code> argument of <code>StatsForecast</code>.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb19"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a>fcst <span class="op">=</span> StatsForecast(df<span class="op">=</span>Y_train_df,</span> +<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a> models<span class="op">=</span>[AutoARIMA(season_length<span class="op">=</span><span class="dv">4</span>)], </span> +<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a> freq<span class="op">=</span><span class="st">'QS'</span>, n_jobs<span class="op">=-</span><span class="dv">1</span>)</span> +<span id="cb19-4"><a href="#cb19-4" aria-hidden="true" tabindex="-1"></a>Y_hat_df <span class="op">=</span> fcst.forecast(h<span class="op">=</span><span class="dv">8</span>, fitted<span class="op">=</span><span class="va">True</span>, level<span class="op">=</span>[<span class="dv">80</span>, <span class="dv">90</span>])</span> +<span id="cb19-5"><a href="#cb19-5" aria-hidden="true" tabindex="-1"></a>Y_fitted_df <span class="op">=</span> fcst.forecast_fitted_values()</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +</section> +<section id="reconcile-forecasts" class="level2"> +<h2 class="anchored" data-anchor-id="reconcile-forecasts">Reconcile forecasts</h2> +<p>The following cell makes the previous forecasts coherent using the <a href="https://Nixtla.github.io/hierarchicalforecast/core.html#hierarchicalreconciliation"><code>HierarchicalReconciliation</code></a> class. Since the hierarchy structure is not strict, we canāt use methods such as <a href="https://Nixtla.github.io/hierarchicalforecast/methods.html#topdown"><code>TopDown</code></a> or <a href="https://Nixtla.github.io/hierarchicalforecast/methods.html#middleout"><code>MiddleOut</code></a>. In this example we use <a href="https://Nixtla.github.io/hierarchicalforecast/methods.html#bottomup"><code>BottomUp</code></a> and <a href="https://Nixtla.github.io/hierarchicalforecast/methods.html#mintrace"><code>MinTrace</code></a>. If you want to calculate prediction intervals, you have to use the <code>level</code> argument as follows.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb20"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a>reconcilers <span class="op">=</span> [</span> +<span id="cb20-2"><a href="#cb20-2" aria-hidden="true" tabindex="-1"></a> BottomUp(),</span> +<span id="cb20-3"><a href="#cb20-3" aria-hidden="true" tabindex="-1"></a> MinTrace(method<span class="op">=</span><span class="st">'mint_shrink'</span>),</span> +<span id="cb20-4"><a href="#cb20-4" aria-hidden="true" tabindex="-1"></a> MinTrace(method<span class="op">=</span><span class="st">'ols'</span>)</span> +<span id="cb20-5"><a href="#cb20-5" aria-hidden="true" tabindex="-1"></a>]</span> +<span id="cb20-6"><a href="#cb20-6" aria-hidden="true" tabindex="-1"></a>hrec <span class="op">=</span> HierarchicalReconciliation(reconcilers<span class="op">=</span>reconcilers)</span> +<span id="cb20-7"><a href="#cb20-7" aria-hidden="true" tabindex="-1"></a>Y_rec_df <span class="op">=</span> hrec.reconcile(Y_hat_df<span class="op">=</span>Y_hat_df, Y_df<span class="op">=</span>Y_fitted_df, </span> +<span id="cb20-8"><a href="#cb20-8" aria-hidden="true" tabindex="-1"></a> S<span class="op">=</span>S_df, tags<span class="op">=</span>tags, level<span class="op">=</span>[<span class="dv">80</span>, <span class="dv">90</span>])</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<p>The dataframe <code>Y_rec_df</code> contains the reconciled forecasts.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb21"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb21-1"><a href="#cb21-1" aria-hidden="true" tabindex="-1"></a>Y_rec_df.head()</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<div> + + +<table class="dataframe table table-sm table-striped small" data-quarto-postprocess="true" data-border="1"> +<thead> +<tr class="header"> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th">ds</th> +<th data-quarto-table-cell-role="th">AutoARIMA</th> +<th data-quarto-table-cell-role="th">AutoARIMA-lo-90</th> +<th data-quarto-table-cell-role="th">AutoARIMA-lo-80</th> +<th data-quarto-table-cell-role="th">AutoARIMA-hi-80</th> +<th data-quarto-table-cell-role="th">AutoARIMA-hi-90</th> +<th data-quarto-table-cell-role="th">AutoARIMA/BottomUp</th> +<th data-quarto-table-cell-role="th">AutoARIMA/BottomUp-lo-90</th> +<th data-quarto-table-cell-role="th">AutoARIMA/BottomUp-lo-80</th> +<th data-quarto-table-cell-role="th">AutoARIMA/BottomUp-hi-80</th> +<th data-quarto-table-cell-role="th">...</th> +<th data-quarto-table-cell-role="th">AutoARIMA/MinTrace_method-mint_shrink</th> +<th data-quarto-table-cell-role="th">AutoARIMA/MinTrace_method-mint_shrink-lo-90</th> +<th data-quarto-table-cell-role="th">AutoARIMA/MinTrace_method-mint_shrink-lo-80</th> +<th data-quarto-table-cell-role="th">AutoARIMA/MinTrace_method-mint_shrink-hi-80</th> +<th data-quarto-table-cell-role="th">AutoARIMA/MinTrace_method-mint_shrink-hi-90</th> +<th data-quarto-table-cell-role="th">AutoARIMA/MinTrace_method-ols</th> +<th data-quarto-table-cell-role="th">AutoARIMA/MinTrace_method-ols-lo-90</th> +<th data-quarto-table-cell-role="th">AutoARIMA/MinTrace_method-ols-lo-80</th> +<th data-quarto-table-cell-role="th">AutoARIMA/MinTrace_method-ols-hi-80</th> +<th data-quarto-table-cell-role="th">AutoARIMA/MinTrace_method-ols-hi-90</th> +</tr> +<tr class="odd"> +<th data-quarto-table-cell-role="th">unique_id</th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td data-quarto-table-cell-role="th">Australia</td> +<td>2016-01-01</td> +<td>26212.554688</td> +<td>24694.224609</td> +<td>25029.580078</td> +<td>27395.527344</td> +<td>27730.884766</td> +<td>24368.099609</td> +<td>23674.076441</td> +<td>23827.366706</td> +<td>24908.832513</td> +<td>...</td> +<td>25205.749397</td> +<td>24453.417115</td> +<td>24619.586229</td> +<td>25791.912565</td> +<td>25958.081679</td> +<td>26059.047512</td> +<td>24978.608364</td> +<td>25217.247087</td> +<td>26900.847937</td> +<td>27139.486661</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">Australia</td> +<td>2016-04-01</td> +<td>25033.667969</td> +<td>23324.066406</td> +<td>23701.669922</td> +<td>26365.666016</td> +<td>26743.269531</td> +<td>22395.921875</td> +<td>21629.482078</td> +<td>21798.767146</td> +<td>22993.076604</td> +<td>...</td> +<td>23720.833190</td> +<td>22915.772233</td> +<td>23093.587632</td> +<td>24348.078748</td> +<td>24525.894148</td> +<td>24769.464257</td> +<td>23554.946551</td> +<td>23823.199470</td> +<td>25715.729045</td> +<td>25983.981963</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">Australia</td> +<td>2016-07-01</td> +<td>24507.027344</td> +<td>22625.500000</td> +<td>23041.076172</td> +<td>25972.978516</td> +<td>26388.554688</td> +<td>22004.169922</td> +<td>21182.945074</td> +<td>21364.330624</td> +<td>22644.009219</td> +<td>...</td> +<td>23167.123691</td> +<td>22316.298074</td> +<td>22504.221604</td> +<td>23830.025777</td> +<td>24017.949308</td> +<td>24205.855344</td> +<td>22870.661086</td> +<td>23165.568073</td> +<td>25246.142616</td> +<td>25541.049603</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">Australia</td> +<td>2016-10-01</td> +<td>25598.929688</td> +<td>23559.919922</td> +<td>24010.281250</td> +<td>27187.578125</td> +<td>27637.937500</td> +<td>22325.056641</td> +<td>21456.892977</td> +<td>21648.645996</td> +<td>23001.467285</td> +<td>...</td> +<td>23982.251913</td> +<td>23087.313715</td> +<td>23284.980478</td> +<td>24679.523348</td> +<td>24877.190111</td> +<td>25271.861336</td> +<td>23825.782311</td> +<td>24145.180634</td> +<td>26398.542038</td> +<td>26717.940362</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">Australia</td> +<td>2017-01-01</td> +<td>26982.578125</td> +<td>24651.535156</td> +<td>25166.396484</td> +<td>28798.757812</td> +<td>29313.619141</td> +<td>23258.001953</td> +<td>22296.178714</td> +<td>22508.618508</td> +<td>24007.385398</td> +<td>...</td> +<td>25002.243615</td> +<td>24016.747195</td> +<td>24234.415731</td> +<td>25770.071498</td> +<td>25987.740034</td> +<td>26611.143736</td> +<td>24959.636647</td> +<td>25324.408272</td> +<td>27897.879201</td> +<td>28262.650825</td> +</tr> +</tbody> +</table> + +<p>5 rows Ć 21 columns</p> +</div> +</div> +</div> +</section> +<section id="plot-forecasts" class="level2"> +<h2 class="anchored" data-anchor-id="plot-forecasts">Plot forecasts</h2> +<p>Then we can plot the probabilistic forecasts using the following function.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb22"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb22-1"><a href="#cb22-1" aria-hidden="true" tabindex="-1"></a>plot_df <span class="op">=</span> pd.concat([Y_df.set_index([<span class="st">'unique_id'</span>, <span class="st">'ds'</span>]), </span> +<span id="cb22-2"><a href="#cb22-2" aria-hidden="true" tabindex="-1"></a> Y_rec_df.set_index(<span class="st">'ds'</span>, append<span class="op">=</span><span class="va">True</span>)], axis<span class="op">=</span><span class="dv">1</span>)</span> +<span id="cb22-3"><a href="#cb22-3" aria-hidden="true" tabindex="-1"></a>plot_df <span class="op">=</span> plot_df.reset_index(<span class="st">'ds'</span>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<section id="plot-single-time-series" class="level3"> +<h3 class="anchored" data-anchor-id="plot-single-time-series">Plot single time series</h3> +<div class="cell"> +<div class="sourceCode cell-code" id="cb23"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb23-1"><a href="#cb23-1" aria-hidden="true" tabindex="-1"></a>hplot.plot_series(</span> +<span id="cb23-2"><a href="#cb23-2" aria-hidden="true" tabindex="-1"></a> series<span class="op">=</span><span class="st">'Australia'</span>,</span> +<span id="cb23-3"><a href="#cb23-3" aria-hidden="true" tabindex="-1"></a> Y_df<span class="op">=</span>plot_df, </span> +<span id="cb23-4"><a href="#cb23-4" aria-hidden="true" tabindex="-1"></a> models<span class="op">=</span>[<span class="st">'y'</span>, <span class="st">'AutoARIMA'</span>, <span class="st">'AutoARIMA/MinTrace_method-ols'</span>],</span> +<span id="cb23-5"><a href="#cb23-5" aria-hidden="true" tabindex="-1"></a> level<span class="op">=</span>[<span class="dv">80</span>]</span> +<span id="cb23-6"><a href="#cb23-6" aria-hidden="true" tabindex="-1"></a>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<p><img src="AustralianDomesticTourism-Intervals_files/figure-html/cell-20-output-1.png" class="img-fluid"></p> +</div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb24"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb24-1"><a href="#cb24-1" aria-hidden="true" tabindex="-1"></a><span class="co"># Since we are plotting a bottom time series</span></span> +<span id="cb24-2"><a href="#cb24-2" aria-hidden="true" tabindex="-1"></a><span class="co"># the probabilistic and mean forecasts</span></span> +<span id="cb24-3"><a href="#cb24-3" aria-hidden="true" tabindex="-1"></a><span class="co"># are the same</span></span> +<span id="cb24-4"><a href="#cb24-4" aria-hidden="true" tabindex="-1"></a>hplot.plot_series(</span> +<span id="cb24-5"><a href="#cb24-5" aria-hidden="true" tabindex="-1"></a> series<span class="op">=</span><span class="st">'Australia/Western Australia/Experience Perth/Visiting'</span>,</span> +<span id="cb24-6"><a href="#cb24-6" aria-hidden="true" tabindex="-1"></a> Y_df<span class="op">=</span>plot_df, </span> +<span id="cb24-7"><a href="#cb24-7" aria-hidden="true" tabindex="-1"></a> models<span class="op">=</span>[<span class="st">'y'</span>, <span class="st">'AutoARIMA'</span>, <span class="st">'AutoARIMA/BottomUp'</span>],</span> +<span id="cb24-8"><a href="#cb24-8" aria-hidden="true" tabindex="-1"></a> level<span class="op">=</span>[<span class="dv">80</span>]</span> +<span id="cb24-9"><a href="#cb24-9" aria-hidden="true" tabindex="-1"></a>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<p><img src="AustralianDomesticTourism-Intervals_files/figure-html/cell-21-output-1.png" class="img-fluid"></p> +</div> +</div> +</section> +<section id="plot-hierarchichally-linked-time-series" class="level3"> +<h3 class="anchored" data-anchor-id="plot-hierarchichally-linked-time-series">Plot hierarchichally linked time series</h3> +<div class="cell"> +<div class="sourceCode cell-code" id="cb25"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb25-1"><a href="#cb25-1" aria-hidden="true" tabindex="-1"></a>hplot.plot_hierarchically_linked_series(</span> +<span id="cb25-2"><a href="#cb25-2" aria-hidden="true" tabindex="-1"></a> bottom_series<span class="op">=</span><span class="st">'Australia/Western Australia/Experience Perth/Visiting'</span>,</span> +<span id="cb25-3"><a href="#cb25-3" aria-hidden="true" tabindex="-1"></a> Y_df<span class="op">=</span>plot_df, </span> +<span id="cb25-4"><a href="#cb25-4" aria-hidden="true" tabindex="-1"></a> models<span class="op">=</span>[<span class="st">'y'</span>, <span class="st">'AutoARIMA'</span>, <span class="st">'AutoARIMA/MinTrace_method-ols'</span>, <span class="st">'AutoARIMA/BottomUp'</span>],</span> +<span id="cb25-5"><a href="#cb25-5" aria-hidden="true" tabindex="-1"></a> level<span class="op">=</span>[<span class="dv">80</span>]</span> +<span id="cb25-6"><a href="#cb25-6" aria-hidden="true" tabindex="-1"></a>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<p><img src="AustralianDomesticTourism-Intervals_files/figure-html/cell-22-output-1.png" class="img-fluid"></p> +</div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb26"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb26-1"><a href="#cb26-1" aria-hidden="true" tabindex="-1"></a><span class="co"># ACT only has Canberra</span></span> +<span id="cb26-2"><a href="#cb26-2" aria-hidden="true" tabindex="-1"></a>hplot.plot_hierarchically_linked_series(</span> +<span id="cb26-3"><a href="#cb26-3" aria-hidden="true" tabindex="-1"></a> bottom_series<span class="op">=</span><span class="st">'Australia/ACT/Canberra/Other'</span>,</span> +<span id="cb26-4"><a href="#cb26-4" aria-hidden="true" tabindex="-1"></a> Y_df<span class="op">=</span>plot_df, </span> +<span id="cb26-5"><a href="#cb26-5" aria-hidden="true" tabindex="-1"></a> models<span class="op">=</span>[<span class="st">'y'</span>, <span class="st">'AutoARIMA/MinTrace_method-mint_shrink'</span>],</span> +<span id="cb26-6"><a href="#cb26-6" aria-hidden="true" tabindex="-1"></a> level<span class="op">=</span>[<span class="dv">80</span>, <span class="dv">90</span>]</span> +<span id="cb26-7"><a href="#cb26-7" aria-hidden="true" tabindex="-1"></a>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<p><img src="AustralianDomesticTourism-Intervals_files/figure-html/cell-23-output-1.png" class="img-fluid"></p> +</div> +</div> +</section> +<section id="references" class="level3"> +<h3 class="anchored" data-anchor-id="references">References</h3> +<ul> +<li><a href="https://otexts.com/fpp3/hierarchical.html">Hyndman, R.J., & Athanasopoulos, G. (2021). āForecasting: principles and practice, 3rd edition: Chapter 11: Forecasting hierarchical and grouped series.ā. OTexts: Melbourne, Australia. OTexts.com/fpp3 Accessed on July 2022.</a></li> +<li><a href="https://robjhyndman.com/publications/mint/">Shanika L. Wickramasuriya, George Athanasopoulos, and Rob J. Hyndman. Optimal forecast reconciliation for hierarchical and grouped time series through trace minimization.Journal of the American Statistical Association, 114(526):804ā819, 2019. doi: 10.1080/01621459.2018.1448825. URL https://robjhyndman.com/publications/mint/.</a></li> +</ul> + + +</section> +</section> + +<p>If you find the code useful, please ā us on <a href="https://github.com/nixtla/hierarchicalforecast">Github</a></p></main> <!-- /main --> +<script id="quarto-html-after-body" type="application/javascript"> +window.document.addEventListener("DOMContentLoaded", function (event) { + const toggleBodyColorMode = (bsSheetEl) => { + const mode = bsSheetEl.getAttribute("data-mode"); + const bodyEl = window.document.querySelector("body"); + if (mode === "dark") { + bodyEl.classList.add("quarto-dark"); + bodyEl.classList.remove("quarto-light"); + } else { + bodyEl.classList.add("quarto-light"); + bodyEl.classList.remove("quarto-dark"); + } + } + const toggleBodyColorPrimary = () => { + const bsSheetEl = window.document.querySelector("link#quarto-bootstrap"); + if (bsSheetEl) { + toggleBodyColorMode(bsSheetEl); + } + } + toggleBodyColorPrimary(); + const icon = "ī§"; + const anchorJS = new window.AnchorJS(); + anchorJS.options = { + placement: 'right', + icon: icon + }; + anchorJS.add('.anchored'); + const isCodeAnnotation = (el) => { + for (const clz of el.classList) { + if (clz.startsWith('code-annotation-')) { + return true; + } + } + return false; + } + const clipboard = new window.ClipboardJS('.code-copy-button', { + text: function(trigger) { + const codeEl = trigger.previousElementSibling.cloneNode(true); + for (const childEl of codeEl.children) { + if (isCodeAnnotation(childEl)) { + childEl.remove(); + } + } + return codeEl.innerText; + } + }); + clipboard.on('success', function(e) { + // button target + const button = e.trigger; + // don't keep focus + button.blur(); + // flash "checked" + button.classList.add('code-copy-button-checked'); + var currentTitle = button.getAttribute("title"); + button.setAttribute("title", "Copied!"); + let tooltip; + if (window.bootstrap) { + button.setAttribute("data-bs-toggle", "tooltip"); + button.setAttribute("data-bs-placement", "left"); + button.setAttribute("data-bs-title", "Copied!"); + tooltip = new bootstrap.Tooltip(button, + { trigger: "manual", + customClass: "code-copy-button-tooltip", + offset: [0, -8]}); + tooltip.show(); + } + setTimeout(function() { + if (tooltip) { + tooltip.hide(); + button.removeAttribute("data-bs-title"); + button.removeAttribute("data-bs-toggle"); + button.removeAttribute("data-bs-placement"); + } + button.setAttribute("title", currentTitle); + button.classList.remove('code-copy-button-checked'); + }, 1000); + // clear code selection + e.clearSelection(); + }); + function tippyHover(el, contentFn) { + const config = { + allowHTML: true, + content: contentFn, + maxWidth: 500, + delay: 100, + arrow: false, + appendTo: function(el) { + return el.parentElement; + }, + interactive: true, + interactiveBorder: 10, + theme: 'quarto', + placement: 'bottom-start' + }; + window.tippy(el, config); + } + const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]'); + for (var i=0; i<noterefs.length; i++) { + const ref = noterefs[i]; + tippyHover(ref, function() { + // use id or data attribute instead here + let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href'); + try { href = new URL(href).hash; } catch {} + const id = href.replace(/^#\/?/, ""); + const note = window.document.getElementById(id); + return note.innerHTML; + }); + } + let selectedAnnoteEl; + const selectorForAnnotation = ( cell, annotation) => { + let cellAttr = 'data-code-cell="' + cell + '"'; + let lineAttr = 'data-code-annotation="' + annotation + '"'; + const selector = 'span[' + cellAttr + '][' + lineAttr + ']'; + return selector; + } + const selectCodeLines = (annoteEl) => { + const doc = window.document; + const targetCell = annoteEl.getAttribute("data-target-cell"); + const targetAnnotation = annoteEl.getAttribute("data-target-annotation"); + const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation)); + const lines = annoteSpan.getAttribute("data-code-lines").split(","); + const lineIds = lines.map((line) => { + return targetCell + "-" + line; + }) + let top = null; + let height = null; + let parent = null; + if (lineIds.length > 0) { + //compute the position of the single el (top and bottom and make a div) + const el = window.document.getElementById(lineIds[0]); + top = el.offsetTop; + height = el.offsetHeight; + parent = el.parentElement.parentElement; + if (lineIds.length > 1) { + const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]); + const bottom = lastEl.offsetTop + lastEl.offsetHeight; + height = bottom - top; + } + if (top !== null && height !== null && parent !== null) { + // cook up a div (if necessary) and position it + let div = window.document.getElementById("code-annotation-line-highlight"); + if (div === null) { + div = window.document.createElement("div"); + div.setAttribute("id", "code-annotation-line-highlight"); + div.style.position = 'absolute'; + parent.appendChild(div); + } + div.style.top = top - 2 + "px"; + div.style.height = height + 4 + "px"; + let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter"); + if (gutterDiv === null) { + gutterDiv = window.document.createElement("div"); + gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter"); + gutterDiv.style.position = 'absolute'; + const codeCell = window.document.getElementById(targetCell); + const gutter = codeCell.querySelector('.code-annotation-gutter'); + gutter.appendChild(gutterDiv); + } + gutterDiv.style.top = top - 2 + "px"; + gutterDiv.style.height = height + 4 + "px"; + } + selectedAnnoteEl = annoteEl; + } + }; + const unselectCodeLines = () => { + const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"]; + elementsIds.forEach((elId) => { + const div = window.document.getElementById(elId); + if (div) { + div.remove(); + } + }); + selectedAnnoteEl = undefined; + }; + // Attach click handler to the DT + const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); + for (const annoteDlNode of annoteDls) { + annoteDlNode.addEventListener('click', (event) => { + const clickedEl = event.target; + if (clickedEl !== selectedAnnoteEl) { + unselectCodeLines(); + const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active'); + if (activeEl) { + activeEl.classList.remove('code-annotation-active'); + } + selectCodeLines(clickedEl); + clickedEl.classList.add('code-annotation-active'); + } else { + // Unselect the line + unselectCodeLines(); + clickedEl.classList.remove('code-annotation-active'); + } + }); + } + const findCites = (el) => { + const parentEl = el.parentElement; + if (parentEl) { + const cites = parentEl.dataset.cites; + if (cites) { + return { + el, + cites: cites.split(' ') + }; + } else { + return findCites(el.parentElement) + } + } else { + return undefined; + } + }; + var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]'); + for (var i=0; i<bibliorefs.length; i++) { + const ref = bibliorefs[i]; + const citeInfo = findCites(ref); + if (citeInfo) { + tippyHover(citeInfo.el, function() { + var popup = window.document.createElement('div'); + citeInfo.cites.forEach(function(cite) { + var citeDiv = window.document.createElement('div'); + citeDiv.classList.add('hanging-indent'); + citeDiv.classList.add('csl-entry'); + var biblioDiv = window.document.getElementById('ref-' + cite); + if (biblioDiv) { + citeDiv.innerHTML = biblioDiv.innerHTML; + } + popup.appendChild(citeDiv); + }); + return popup.innerHTML; + }); + } + } +}); +</script> +</div> <!-- /content --> + + + +</body></html> \ No newline at end of file diff --git a/examples/australiandomestictourism-permbu-intervals.html b/examples/australiandomestictourism-permbu-intervals.html new file mode 100644 index 00000000..378c04b2 --- /dev/null +++ b/examples/australiandomestictourism-permbu-intervals.html @@ -0,0 +1,1273 @@ +<!DOCTYPE html> +<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head> + +<meta charset="utf-8"> +<meta name="generator" content="quarto-1.3.450"> + +<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes"> + + +<title>hierarchicalforecast - PERMBU</title> +<style> +code{white-space: pre-wrap;} +span.smallcaps{font-variant: small-caps;} +div.columns{display: flex; gap: min(4vw, 1.5em);} +div.column{flex: auto; overflow-x: auto;} +div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;} +ul.task-list{list-style: none;} +ul.task-list li input[type="checkbox"] { + width: 0.8em; + margin: 0 0.8em 0.2em -1em; /* quarto-specific, see https://github.com/quarto-dev/quarto-cli/issues/4556 */ + vertical-align: middle; +} +/* CSS for syntax highlighting */ +pre > code.sourceCode { white-space: pre; position: relative; } +pre > code.sourceCode > span { display: inline-block; line-height: 1.25; } +pre > code.sourceCode > span:empty { height: 1.2em; } +.sourceCode { overflow: visible; } +code.sourceCode > span { color: inherit; text-decoration: inherit; } +div.sourceCode { margin: 1em 0; } +pre.sourceCode { margin: 0; } +@media screen { +div.sourceCode { overflow: auto; } +} +@media print { +pre > code.sourceCode { white-space: pre-wrap; } +pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; } +} +pre.numberSource code + { counter-reset: source-line 0; } +pre.numberSource code > span + { position: relative; left: -4em; counter-increment: source-line; } +pre.numberSource code > span > a:first-child::before + { content: counter(source-line); + position: relative; left: -1em; text-align: right; vertical-align: baseline; + border: none; display: inline-block; + -webkit-touch-callout: none; -webkit-user-select: none; + -khtml-user-select: none; -moz-user-select: none; + -ms-user-select: none; user-select: none; + padding: 0 4px; width: 4em; + } +pre.numberSource { margin-left: 3em; padding-left: 4px; } +div.sourceCode + { } +@media screen { +pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; } +} +</style> + + +<script src="../site_libs/quarto-nav/quarto-nav.js"></script> +<script src="../site_libs/quarto-nav/headroom.min.js"></script> +<script src="../site_libs/clipboard/clipboard.min.js"></script> +<script src="../site_libs/quarto-search/autocomplete.umd.js"></script> +<script src="../site_libs/quarto-search/fuse.min.js"></script> +<script src="../site_libs/quarto-search/quarto-search.js"></script> +<meta name="quarto:offset" content="../"> +<link href="../favicon_png.png" rel="icon" type="image/png"> +<script src="../site_libs/quarto-html/quarto.js"></script> +<script src="../site_libs/quarto-html/popper.min.js"></script> +<script src="../site_libs/quarto-html/tippy.umd.min.js"></script> +<script src="../site_libs/quarto-html/anchor.min.js"></script> +<link href="../site_libs/quarto-html/tippy.css" rel="stylesheet"> +<link href="../site_libs/quarto-html/quarto-syntax-highlighting.css" rel="stylesheet" id="quarto-text-highlighting-styles"> +<script src="../site_libs/bootstrap/bootstrap.min.js"></script> +<link href="../site_libs/bootstrap/bootstrap-icons.css" rel="stylesheet"> +<link href="../site_libs/bootstrap/bootstrap.min.css" rel="stylesheet" id="quarto-bootstrap" data-mode="light"> +<script id="quarto-search-options" type="application/json">{ + "location": "navbar", + "copy-button": false, + "collapse-after": 3, + "panel-placement": "end", + "type": "overlay", + "limit": 20, + "language": { + "search-no-results-text": "No results", + "search-matching-documents-text": "matching documents", + "search-copy-link-title": "Copy link to search", + "search-hide-matches-text": "Hide additional matches", + "search-more-match-text": "more match in this document", + "search-more-matches-text": "more matches in this document", + "search-clear-button-title": "Clear", + "search-detached-cancel-button-title": "Cancel", + "search-submit-button-title": "Submit", + "search-label": "Search" + } +}</script> +<script async="" src="https://www.googletagmanager.com/gtag/js?id=G-NXJNCVR18L"></script> + +<script type="text/javascript"> + +window.dataLayer = window.dataLayer || []; +function gtag(){dataLayer.push(arguments);} +gtag('js', new Date()); +gtag('config', 'G-NXJNCVR18L', { 'anonymize_ip': true}); +</script> +<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js" integrity="sha512-c3Nl8+7g4LMSTdrm621y7kf9v3SDPnhxLNhcjFJbKECVnmZHTdo+IRO05sNLTH/D3vA6u1X32ehoLC7WFVdheg==" crossorigin="anonymous"></script> +<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js" integrity="sha512-bLT0Qm9VnAYZDflyKcBaQ2gg0hSYNQrJ8RilYldYQ1FxQYoCLtUjuuRuZo+fjqhx/qtq/1itJ0C2ejDxltZVFg==" crossorigin="anonymous"></script> +<script type="application/javascript">define('jquery', [],function() {return window.jQuery;})</script> + + +<link rel="stylesheet" href="../styles.css"> +<meta property="og:title" content="hierarchicalforecast - PERMBU"> +<meta property="og:description" content=""> +<meta property="og:image" content="https://colab.research.google.com/assets/colab-badge.svg"> +<meta property="og:site-name" content="hierarchicalforecast"> +<meta name="twitter:title" content="hierarchicalforecast - PERMBU"> +<meta name="twitter:description" content=""> +<meta name="twitter:image" content="https://colab.research.google.com/assets/colab-badge.svg"> +<meta name="twitter:card" content="summary_large_image"> +</head> + +<body class="nav-sidebar floating nav-fixed"> + +<div id="quarto-search-results"></div> + <header id="quarto-header" class="headroom fixed-top"> + <nav class="navbar navbar-expand-lg navbar-dark "> + <div class="navbar-container container-fluid"> + <div class="navbar-brand-container"> + <a class="navbar-brand" href="../index.html"> + <span class="navbar-title">hierarchicalforecast</span> + </a> + </div> + <div id="quarto-search" class="" title="Search"></div> + <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + <span class="navbar-toggler-icon"></span> +</button> + <div class="collapse navbar-collapse" id="navbarCollapse"> + <ul class="navbar-nav navbar-nav-scroll me-auto"> + <li class="nav-item"> + <a class="nav-link active" href="../examples/tourismsmall.html" rel="" target="" aria-current="page"> + <span class="menu-text">Get Started</span></a> + </li> + <li class="nav-item dropdown "> + <a class="nav-link dropdown-toggle" href="#" id="nav-menu-nixtlaverse" role="button" data-bs-toggle="dropdown" aria-expanded="false" rel="" target=""> + <span class="menu-text">NixtlaVerse</span> + </a> + <ul class="dropdown-menu" aria-labelledby="nav-menu-nixtlaverse"> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/mlforecast" rel="" target=""> + <span class="dropdown-text">MLForecast š¤</span></a> + </li> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/neuralforecast" rel="" target=""> + <span class="dropdown-text">NeuralForecast š§ </span></a> + </li> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/statsforecast" rel="" target=""> + <span class="dropdown-text">StatsForecast ā”ļø</span></a> + </li> + </ul> + </li> + <li class="nav-item dropdown "> + <a class="nav-link dropdown-toggle" href="#" id="nav-menu-help" role="button" data-bs-toggle="dropdown" aria-expanded="false" rel="" target=""> + <span class="menu-text">Help</span> + </a> + <ul class="dropdown-menu" aria-labelledby="nav-menu-help"> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/hierarchicalforecast/issues/new/choose" rel="" target=""><i class="bi bi-bug" role="img"> +</i> + <span class="dropdown-text">Report an Issue</span></a> + </li> + <li> + <a class="dropdown-item" href="https://join.slack.com/t/nixtlacommunity/shared_invite/zt-1kd5m5db7-7OOfy0xVNf1PcvCiAPWvPw" rel="" target=""><i class="bi bi-chat-right-text" role="img"> +</i> + <span class="dropdown-text">Join our Slack</span></a> + </li> + </ul> + </li> +</ul> + <ul class="navbar-nav navbar-nav-scroll ms-auto"> + <li class="nav-item compact"> + <a class="nav-link" href="https://github.com/nixtla/hierarchicalforecast" rel="" target=""><i class="bi bi-github" role="img"> +</i> + <span class="menu-text"></span></a> + </li> + <li class="nav-item compact"> + <a class="nav-link" href="https://twitter.com/nixtlainc" rel="" target=""><i class="bi bi-twitter" role="img" aria-label="Nixtla Twitter"> +</i> + <span class="menu-text"></span></a> + </li> +</ul> + <div class="quarto-navbar-tools"> +</div> + </div> <!-- /navcollapse --> + </div> <!-- /container-fluid --> + </nav> + <nav class="quarto-secondary-nav"> + <div class="container-fluid d-flex"> + <button type="button" class="quarto-btn-toggle btn" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + <i class="bi bi-layout-text-sidebar-reverse"></i> + </button> + <nav class="quarto-page-breadcrumbs" aria-label="breadcrumb"><ol class="breadcrumb"><li class="breadcrumb-item">Tutorials</li><li class="breadcrumb-item"><a href="../examples/australiandomestictourism-intervals.html">Probabilistic Reconciliation</a></li><li class="breadcrumb-item"><a href="../examples/australiandomestictourism-permbu-intervals.html">PERMBU</a></li></ol></nav> + <a class="flex-grow-1" role="button" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + </a> + </div> + </nav> +</header> +<!-- content --> +<div id="quarto-content" class="quarto-container page-columns page-rows-contents page-layout-article page-navbar"> +<!-- sidebar --> + <nav id="quarto-sidebar" class="sidebar collapse collapse-horizontal sidebar-navigation floating overflow-auto"> + <div class="sidebar-menu-container"> + <ul class="list-unstyled mt-1"> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../index.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Hierarchical Forecast š</span></a> + </div> +</li> + <li class="px-0"><hr class="sidebar-divider hi "></li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-1" aria-expanded="false"> + <span class="menu-text">Getting Started</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-1" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-1" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/installation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Install</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/tourismsmall.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Reconciliation Quick Start</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/introduction.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Introduction</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-2" aria-expanded="true"> + <span class="menu-text">Tutorials</span></a> + <a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-2" aria-expanded="true" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-2" class="collapse list-unstyled sidebar-section depth1 show"> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-3" aria-expanded="false"> + <span class="menu-text">Point Reconciliation</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-3" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-3" class="collapse list-unstyled sidebar-section depth2 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Geographical Aggregation (Tourism)</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australianprisonpopulation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Geographical Aggregation (Prison Population)</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/nonnegativereconciliation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Non-Negative MinTrace</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-4" aria-expanded="true"> + <span class="menu-text">Probabilistic Reconciliation</span></a> + <a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-4" aria-expanded="true" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-4" class="collapse list-unstyled sidebar-section depth2 show"> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Normality</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism-bootstraped-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Bootstrap</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism-permbu-intervals.html" class="sidebar-item-text sidebar-link active"> + <span class="menu-text">PERMBU</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/tourismlarge-evaluation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Probabilistic Forecast Evaluation</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-5" aria-expanded="false"> + <span class="menu-text">ML Forecast Reconciliation</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-5" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-5" class="collapse list-unstyled sidebar-section depth2 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/hierarchicalforecast-gluonts.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">GluonTS</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/mlframeworksexample.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Neural/MLForecast</span></a> + </div> +</li> + </ul> + </li> + </ul> + </li> + <li class="sidebar-item"> + <span class="menu-text">Methods</span> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-6" aria-expanded="false"> + <span class="menu-text">API Reference</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-6" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-6" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../core.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Core </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../methods.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Reconciliation Methods </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../probabilistic_methods.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Probabilistic Methods </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../evaluation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Hierarchical Evaluation</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../utils.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Aggregation/Visualization Utils</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-7" aria-expanded="false"> + <span class="menu-text">Community</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-7" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-7" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item"> + <span class="menu-text">Contributing</span> + </li> + </ul> + </li> + </ul> + </div> +</nav> +<div id="quarto-sidebar-glass" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass"></div> +<!-- margin-sidebar --> + <div id="quarto-margin-sidebar" class="sidebar margin-sidebar"> + <nav id="TOC" role="doc-toc" class="toc-active"> + <h2 id="toc-title">On this page</h2> + + <ul> + <li><a href="#aggregate-bottom-time-series" id="toc-aggregate-bottom-time-series" class="nav-link active" data-scroll-target="#aggregate-bottom-time-series">Aggregate bottom time series</a> + <ul class="collapse"> + <li><a href="#split-traintest-sets" id="toc-split-traintest-sets" class="nav-link" data-scroll-target="#split-traintest-sets">Split Train/Test sets</a></li> + </ul></li> + <li><a href="#computing-base-forecasts" id="toc-computing-base-forecasts" class="nav-link" data-scroll-target="#computing-base-forecasts">Computing base forecasts</a></li> + <li><a href="#reconcile-forecasts-and-compute-prediction-intervals-using-permbu" id="toc-reconcile-forecasts-and-compute-prediction-intervals-using-permbu" class="nav-link" data-scroll-target="#reconcile-forecasts-and-compute-prediction-intervals-using-permbu">Reconcile forecasts and compute prediction intervals using PERMBU</a></li> + <li><a href="#plot-forecasts" id="toc-plot-forecasts" class="nav-link" data-scroll-target="#plot-forecasts">Plot forecasts</a> + <ul class="collapse"> + <li><a href="#plot-single-time-series" id="toc-plot-single-time-series" class="nav-link" data-scroll-target="#plot-single-time-series">Plot single time series</a></li> + <li><a href="#plot-hierarchichally-linked-time-series" id="toc-plot-hierarchichally-linked-time-series" class="nav-link" data-scroll-target="#plot-hierarchichally-linked-time-series">Plot hierarchichally linked time series</a></li> + <li><a href="#references" id="toc-references" class="nav-link" data-scroll-target="#references">References</a></li> + </ul></li> + </ul> +<div class="toc-actions"><div><i class="bi bi-github"></i></div><div class="action-links"><p><a href="https://github.com/Nixtla/hierarchicalforecast/issues/new" class="toc-action">Report an issue</a></p></div></div></nav> + </div> +<!-- main --> +<main class="content" id="quarto-document-content"> + +<header id="title-block-header" class="quarto-title-block default"> +<div class="quarto-title"> +<h1 class="title">PERMBU</h1> +</div> + + + +<div class="quarto-title-meta"> + + + + + </div> + + +</header> + +<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! --> +<p><a href="https://colab.research.google.com/github/Nixtla/hierarchicalforecast/blob/main/nbs/examples/AustralianDomesticTourism-Permbu-Intervals.ipynb" target="_parent"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"></a></p> +<p>In many cases, only the time series at the lowest level of the hierarchies (bottom time series) are available. <code>HierarchicalForecast</code> has tools to create time series for all hierarchies and also allows you to calculate prediction intervals for all hierarchies. In this notebook we will see how to do it.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb1"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="op">!</span>pip install hierarchicalforecast statsforecast</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb2"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> numpy <span class="im">as</span> np</span> +<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> pandas <span class="im">as</span> pd</span> +<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> matplotlib.pyplot <span class="im">as</span> plt</span> +<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a><span class="co"># compute base forecast no coherent</span></span> +<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> statsforecast.models <span class="im">import</span> AutoARIMA</span> +<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> statsforecast.core <span class="im">import</span> StatsForecast</span> +<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a><span class="co">#obtain hierarchical reconciliation methods and evaluation</span></span> +<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> hierarchicalforecast.methods <span class="im">import</span> BottomUp, MinTrace</span> +<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> hierarchicalforecast.utils <span class="im">import</span> aggregate, HierarchicalPlot</span> +<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> hierarchicalforecast.core <span class="im">import</span> HierarchicalReconciliation</span> +<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> hierarchicalforecast.evaluation <span class="im">import</span> HierarchicalEvaluation</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-stderr"> +<pre><code>/Users/fedex/miniconda3/envs/hierarchicalforecast/lib/python3.10/site-packages/statsforecast/core.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html + from tqdm.autonotebook import tqdm</code></pre> +</div> +</div> +<section id="aggregate-bottom-time-series" class="level2"> +<h2 class="anchored" data-anchor-id="aggregate-bottom-time-series">Aggregate bottom time series</h2> +<p>In this example we will use the <a href="https://otexts.com/fpp3/tourism.html">Tourism</a> dataset from the <a href="https://otexts.com/fpp3/">Forecasting: Principles and Practice</a> book. The dataset only contains the time series at the lowest level, so we need to create the time series for all hierarchies.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb4"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a>Y_df <span class="op">=</span> pd.read_csv(<span class="st">'https://raw.githubusercontent.com/Nixtla/transfer-learning-time-series/main/datasets/tourism.csv'</span>)</span> +<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>Y_df <span class="op">=</span> Y_df.rename({<span class="st">'Trips'</span>: <span class="st">'y'</span>, <span class="st">'Quarter'</span>: <span class="st">'ds'</span>}, axis<span class="op">=</span><span class="dv">1</span>)</span> +<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>Y_df.insert(<span class="dv">0</span>, <span class="st">'Country'</span>, <span class="st">'Australia'</span>)</span> +<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>Y_df <span class="op">=</span> Y_df[[<span class="st">'Country'</span>, <span class="st">'Region'</span>, <span class="st">'State'</span>, <span class="st">'Purpose'</span>, <span class="st">'ds'</span>, <span class="st">'y'</span>]]</span> +<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>Y_df[<span class="st">'ds'</span>] <span class="op">=</span> Y_df[<span class="st">'ds'</span>].<span class="bu">str</span>.replace(<span class="vs">r'(\d+) (Q\d)'</span>, <span class="vs">r'\1-\2'</span>, regex<span class="op">=</span><span class="va">True</span>)</span> +<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>Y_df[<span class="st">'ds'</span>] <span class="op">=</span> pd.to_datetime(Y_df[<span class="st">'ds'</span>])</span> +<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>Y_df.head()</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<div> + + +<table class="dataframe table table-sm table-striped small" data-quarto-postprocess="true" data-border="1"> +<thead> +<tr class="header"> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th">Country</th> +<th data-quarto-table-cell-role="th">Region</th> +<th data-quarto-table-cell-role="th">State</th> +<th data-quarto-table-cell-role="th">Purpose</th> +<th data-quarto-table-cell-role="th">ds</th> +<th data-quarto-table-cell-role="th">y</th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td data-quarto-table-cell-role="th">0</td> +<td>Australia</td> +<td>Adelaide</td> +<td>South Australia</td> +<td>Business</td> +<td>1998-01-01</td> +<td>135.077690</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">1</td> +<td>Australia</td> +<td>Adelaide</td> +<td>South Australia</td> +<td>Business</td> +<td>1998-04-01</td> +<td>109.987316</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">2</td> +<td>Australia</td> +<td>Adelaide</td> +<td>South Australia</td> +<td>Business</td> +<td>1998-07-01</td> +<td>166.034687</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">3</td> +<td>Australia</td> +<td>Adelaide</td> +<td>South Australia</td> +<td>Business</td> +<td>1998-10-01</td> +<td>127.160464</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">4</td> +<td>Australia</td> +<td>Adelaide</td> +<td>South Australia</td> +<td>Business</td> +<td>1999-01-01</td> +<td>137.448533</td> +</tr> +</tbody> +</table> + +</div> +</div> +</div> +<p>The dataset can be grouped in the following strictly hierarchical structure.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb5"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a>spec <span class="op">=</span> [</span> +<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a> [<span class="st">'Country'</span>],</span> +<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a> [<span class="st">'Country'</span>, <span class="st">'State'</span>], </span> +<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a> [<span class="st">'Country'</span>, <span class="st">'State'</span>, <span class="st">'Region'</span>]</span> +<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>]</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<p>Using the <a href="https://Nixtla.github.io/hierarchicalforecast/utils.html#aggregate"><code>aggregate</code></a> function from <code>HierarchicalForecast</code> we can get the full set of time series.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb6"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a>Y_df, S_df, tags <span class="op">=</span> aggregate(df<span class="op">=</span>Y_df, spec<span class="op">=</span>spec)</span> +<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>Y_df <span class="op">=</span> Y_df.reset_index()</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-stderr"> +<pre><code>/Users/fedex/miniconda3/envs/hierarchicalforecast/lib/python3.10/site-packages/sklearn/preprocessing/_encoders.py:828: FutureWarning: `sparse` was renamed to `sparse_output` in version 1.2 and will be removed in 1.4. `sparse_output` is ignored unless you leave `sparse` to its default value. + warnings.warn(</code></pre> +</div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb8"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a>Y_df.head()</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<div> + + +<table class="dataframe table table-sm table-striped small" data-quarto-postprocess="true" data-border="1"> +<thead> +<tr class="header"> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th">unique_id</th> +<th data-quarto-table-cell-role="th">ds</th> +<th data-quarto-table-cell-role="th">y</th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td data-quarto-table-cell-role="th">0</td> +<td>Australia</td> +<td>1998-01-01</td> +<td>23182.197269</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">1</td> +<td>Australia</td> +<td>1998-04-01</td> +<td>20323.380067</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">2</td> +<td>Australia</td> +<td>1998-07-01</td> +<td>19826.640511</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">3</td> +<td>Australia</td> +<td>1998-10-01</td> +<td>20830.129891</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">4</td> +<td>Australia</td> +<td>1999-01-01</td> +<td>22087.353380</td> +</tr> +</tbody> +</table> + +</div> +</div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb9"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a>S_df.iloc[:<span class="dv">5</span>, :<span class="dv">5</span>]</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<div> + + +<table class="dataframe table table-sm table-striped small" data-quarto-postprocess="true" data-border="1"> +<thead> +<tr class="header"> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th">Australia/ACT/Canberra</th> +<th data-quarto-table-cell-role="th">Australia/New South Wales/Blue Mountains</th> +<th data-quarto-table-cell-role="th">Australia/New South Wales/Capital Country</th> +<th data-quarto-table-cell-role="th">Australia/New South Wales/Central Coast</th> +<th data-quarto-table-cell-role="th">Australia/New South Wales/Central NSW</th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td data-quarto-table-cell-role="th">Australia</td> +<td>1.0</td> +<td>1.0</td> +<td>1.0</td> +<td>1.0</td> +<td>1.0</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">Australia/ACT</td> +<td>1.0</td> +<td>0.0</td> +<td>0.0</td> +<td>0.0</td> +<td>0.0</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">Australia/New South Wales</td> +<td>0.0</td> +<td>1.0</td> +<td>1.0</td> +<td>1.0</td> +<td>1.0</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">Australia/Northern Territory</td> +<td>0.0</td> +<td>0.0</td> +<td>0.0</td> +<td>0.0</td> +<td>0.0</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">Australia/Queensland</td> +<td>0.0</td> +<td>0.0</td> +<td>0.0</td> +<td>0.0</td> +<td>0.0</td> +</tr> +</tbody> +</table> + +</div> +</div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb10"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a>tags[<span class="st">'Country/State'</span>]</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<pre><code>array(['Australia/ACT', 'Australia/New South Wales', + 'Australia/Northern Territory', 'Australia/Queensland', + 'Australia/South Australia', 'Australia/Tasmania', + 'Australia/Victoria', 'Australia/Western Australia'], dtype=object)</code></pre> +</div> +</div> +<p>We can visualize the <code>S</code> matrix and the data using the <a href="https://Nixtla.github.io/hierarchicalforecast/utils.html#hierarchicalplot"><code>HierarchicalPlot</code></a> class as follows.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb12"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a>hplot <span class="op">=</span> HierarchicalPlot(S<span class="op">=</span>S_df, tags<span class="op">=</span>tags)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb13"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a>hplot.plot_summing_matrix()</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<p><img src="AustralianDomesticTourism-Permbu-Intervals_files/figure-html/cell-11-output-1.png" class="img-fluid"></p> +</div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb14"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a>hplot.plot_hierarchically_linked_series(</span> +<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a> bottom_series<span class="op">=</span><span class="st">'Australia/ACT/Canberra'</span>,</span> +<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a> Y_df<span class="op">=</span>Y_df.set_index(<span class="st">'unique_id'</span>)</span> +<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<p><img src="AustralianDomesticTourism-Permbu-Intervals_files/figure-html/cell-12-output-1.png" class="img-fluid"></p> +</div> +</div> +<section id="split-traintest-sets" class="level3"> +<h3 class="anchored" data-anchor-id="split-traintest-sets">Split Train/Test sets</h3> +<p>We use the final two years (8 quarters) as test set.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb15"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a>Y_test_df <span class="op">=</span> Y_df.groupby(<span class="st">'unique_id'</span>).tail(<span class="dv">8</span>)</span> +<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a>Y_train_df <span class="op">=</span> Y_df.drop(Y_test_df.index)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb16"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a>Y_test_df <span class="op">=</span> Y_test_df.set_index(<span class="st">'unique_id'</span>)</span> +<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a>Y_train_df <span class="op">=</span> Y_train_df.set_index(<span class="st">'unique_id'</span>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb17"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a>Y_train_df.groupby(<span class="st">'unique_id'</span>).size()</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<pre><code>unique_id +Australia 72 +Australia/ACT 72 +Australia/ACT/Canberra 72 +Australia/New South Wales 72 +Australia/New South Wales/Blue Mountains 72 + .. +Australia/Western Australia/Australia's Coral Coast 72 +Australia/Western Australia/Australia's Golden Outback 72 +Australia/Western Australia/Australia's North West 72 +Australia/Western Australia/Australia's South West 72 +Australia/Western Australia/Experience Perth 72 +Length: 85, dtype: int64</code></pre> +</div> +</div> +</section> +</section> +<section id="computing-base-forecasts" class="level2"> +<h2 class="anchored" data-anchor-id="computing-base-forecasts">Computing base forecasts</h2> +<p>The following cell computes the <strong>base forecasts</strong> for each time series in <code>Y_df</code> using the <code>AutoARIMA</code> and model. Observe that <code>Y_hat_df</code> contains the forecasts but they are not coherent. To reconcile the prediction intervals we need to calculate the uncoherent intervals using the <code>level</code> argument of <code>StatsForecast</code>.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb19"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a>fcst <span class="op">=</span> StatsForecast(df<span class="op">=</span>Y_train_df,</span> +<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a> models<span class="op">=</span>[AutoARIMA(season_length<span class="op">=</span><span class="dv">4</span>)], </span> +<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a> freq<span class="op">=</span><span class="st">'QS'</span>, n_jobs<span class="op">=-</span><span class="dv">1</span>)</span> +<span id="cb19-4"><a href="#cb19-4" aria-hidden="true" tabindex="-1"></a>Y_hat_df <span class="op">=</span> fcst.forecast(h<span class="op">=</span><span class="dv">8</span>, fitted<span class="op">=</span><span class="va">True</span>, level<span class="op">=</span>[<span class="dv">80</span>, <span class="dv">90</span>])</span> +<span id="cb19-5"><a href="#cb19-5" aria-hidden="true" tabindex="-1"></a>Y_fitted_df <span class="op">=</span> fcst.forecast_fitted_values()</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +</section> +<section id="reconcile-forecasts-and-compute-prediction-intervals-using-permbu" class="level2"> +<h2 class="anchored" data-anchor-id="reconcile-forecasts-and-compute-prediction-intervals-using-permbu">Reconcile forecasts and compute prediction intervals using PERMBU</h2> +<p>The following cell makes the previous forecasts coherent using the <a href="https://Nixtla.github.io/hierarchicalforecast/core.html#hierarchicalreconciliation"><code>HierarchicalReconciliation</code></a> class. In this example we use <a href="https://Nixtla.github.io/hierarchicalforecast/methods.html#bottomup"><code>BottomUp</code></a> and <a href="https://Nixtla.github.io/hierarchicalforecast/methods.html#mintrace"><code>MinTrace</code></a>. If you want to calculate prediction intervals, you have to use the <code>level</code> argument as follows and also <code>intervals_method='permbu'</code>.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb20"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a>reconcilers <span class="op">=</span> [</span> +<span id="cb20-2"><a href="#cb20-2" aria-hidden="true" tabindex="-1"></a> BottomUp(),</span> +<span id="cb20-3"><a href="#cb20-3" aria-hidden="true" tabindex="-1"></a> MinTrace(method<span class="op">=</span><span class="st">'mint_shrink'</span>),</span> +<span id="cb20-4"><a href="#cb20-4" aria-hidden="true" tabindex="-1"></a> MinTrace(method<span class="op">=</span><span class="st">'ols'</span>)</span> +<span id="cb20-5"><a href="#cb20-5" aria-hidden="true" tabindex="-1"></a>]</span> +<span id="cb20-6"><a href="#cb20-6" aria-hidden="true" tabindex="-1"></a>hrec <span class="op">=</span> HierarchicalReconciliation(reconcilers<span class="op">=</span>reconcilers)</span> +<span id="cb20-7"><a href="#cb20-7" aria-hidden="true" tabindex="-1"></a>Y_rec_df <span class="op">=</span> hrec.reconcile(Y_hat_df<span class="op">=</span>Y_hat_df, Y_df<span class="op">=</span>Y_fitted_df,</span> +<span id="cb20-8"><a href="#cb20-8" aria-hidden="true" tabindex="-1"></a> S<span class="op">=</span>S_df, tags<span class="op">=</span>tags,</span> +<span id="cb20-9"><a href="#cb20-9" aria-hidden="true" tabindex="-1"></a> level<span class="op">=</span>[<span class="dv">80</span>, <span class="dv">90</span>], intervals_method<span class="op">=</span><span class="st">'permbu'</span>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-stderr"> +<pre><code>/Users/fedex/miniconda3/envs/hierarchicalforecast/lib/python3.10/site-packages/sklearn/preprocessing/_encoders.py:828: FutureWarning: `sparse` was renamed to `sparse_output` in version 1.2 and will be removed in 1.4. `sparse_output` is ignored unless you leave `sparse` to its default value. + warnings.warn( +/Users/fedex/miniconda3/envs/hierarchicalforecast/lib/python3.10/site-packages/sklearn/preprocessing/_encoders.py:828: FutureWarning: `sparse` was renamed to `sparse_output` in version 1.2 and will be removed in 1.4. `sparse_output` is ignored unless you leave `sparse` to its default value. + warnings.warn( +/Users/fedex/miniconda3/envs/hierarchicalforecast/lib/python3.10/site-packages/sklearn/preprocessing/_encoders.py:828: FutureWarning: `sparse` was renamed to `sparse_output` in version 1.2 and will be removed in 1.4. `sparse_output` is ignored unless you leave `sparse` to its default value. + warnings.warn( +/Users/fedex/miniconda3/envs/hierarchicalforecast/lib/python3.10/site-packages/sklearn/preprocessing/_encoders.py:828: FutureWarning: `sparse` was renamed to `sparse_output` in version 1.2 and will be removed in 1.4. `sparse_output` is ignored unless you leave `sparse` to its default value. + warnings.warn( +/Users/fedex/miniconda3/envs/hierarchicalforecast/lib/python3.10/site-packages/sklearn/preprocessing/_encoders.py:828: FutureWarning: `sparse` was renamed to `sparse_output` in version 1.2 and will be removed in 1.4. `sparse_output` is ignored unless you leave `sparse` to its default value. + warnings.warn( +/Users/fedex/miniconda3/envs/hierarchicalforecast/lib/python3.10/site-packages/sklearn/preprocessing/_encoders.py:828: FutureWarning: `sparse` was renamed to `sparse_output` in version 1.2 and will be removed in 1.4. `sparse_output` is ignored unless you leave `sparse` to its default value. + warnings.warn(</code></pre> +</div> +</div> +<p>The dataframe <code>Y_rec_df</code> contains the reconciled forecasts.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb22"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb22-1"><a href="#cb22-1" aria-hidden="true" tabindex="-1"></a>Y_rec_df.head()</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<div> + + +<table class="dataframe table table-sm table-striped small" data-quarto-postprocess="true" data-border="1"> +<thead> +<tr class="header"> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th">ds</th> +<th data-quarto-table-cell-role="th">AutoARIMA</th> +<th data-quarto-table-cell-role="th">AutoARIMA-lo-90</th> +<th data-quarto-table-cell-role="th">AutoARIMA-lo-80</th> +<th data-quarto-table-cell-role="th">AutoARIMA-hi-80</th> +<th data-quarto-table-cell-role="th">AutoARIMA-hi-90</th> +<th data-quarto-table-cell-role="th">AutoARIMA/BottomUp</th> +<th data-quarto-table-cell-role="th">AutoARIMA/BottomUp-lo-90</th> +<th data-quarto-table-cell-role="th">AutoARIMA/BottomUp-lo-80</th> +<th data-quarto-table-cell-role="th">AutoARIMA/BottomUp-hi-80</th> +<th data-quarto-table-cell-role="th">...</th> +<th data-quarto-table-cell-role="th">AutoARIMA/MinTrace_method-mint_shrink</th> +<th data-quarto-table-cell-role="th">AutoARIMA/MinTrace_method-mint_shrink-lo-90</th> +<th data-quarto-table-cell-role="th">AutoARIMA/MinTrace_method-mint_shrink-lo-80</th> +<th data-quarto-table-cell-role="th">AutoARIMA/MinTrace_method-mint_shrink-hi-80</th> +<th data-quarto-table-cell-role="th">AutoARIMA/MinTrace_method-mint_shrink-hi-90</th> +<th data-quarto-table-cell-role="th">AutoARIMA/MinTrace_method-ols</th> +<th data-quarto-table-cell-role="th">AutoARIMA/MinTrace_method-ols-lo-90</th> +<th data-quarto-table-cell-role="th">AutoARIMA/MinTrace_method-ols-lo-80</th> +<th data-quarto-table-cell-role="th">AutoARIMA/MinTrace_method-ols-hi-80</th> +<th data-quarto-table-cell-role="th">AutoARIMA/MinTrace_method-ols-hi-90</th> +</tr> +<tr class="odd"> +<th data-quarto-table-cell-role="th">unique_id</th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td data-quarto-table-cell-role="th">Australia</td> +<td>2016-01-01</td> +<td>26212.554688</td> +<td>24694.224609</td> +<td>25029.580078</td> +<td>27395.527344</td> +<td>27730.884766</td> +<td>24865.636719</td> +<td>24106.802510</td> +<td>24373.962043</td> +<td>25423.566450</td> +<td>...</td> +<td>25395.411928</td> +<td>24733.046633</td> +<td>24824.274681</td> +<td>25939.345007</td> +<td>25998.692460</td> +<td>26133.758953</td> +<td>25516.484518</td> +<td>25600.644926</td> +<td>26662.923204</td> +<td>26855.585562</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">Australia</td> +<td>2016-04-01</td> +<td>25033.667969</td> +<td>23324.066406</td> +<td>23701.669922</td> +<td>26365.666016</td> +<td>26743.269531</td> +<td>23247.097656</td> +<td>22696.597930</td> +<td>22821.256357</td> +<td>23830.632567</td> +<td>...</td> +<td>23986.272540</td> +<td>23289.811432</td> +<td>23525.630785</td> +<td>24563.998645</td> +<td>24739.826238</td> +<td>24934.260399</td> +<td>24402.570904</td> +<td>24481.968560</td> +<td>25567.085565</td> +<td>25696.312229</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">Australia</td> +<td>2016-07-01</td> +<td>24507.027344</td> +<td>22625.500000</td> +<td>23041.076172</td> +<td>25972.978516</td> +<td>26388.554688</td> +<td>22658.207031</td> +<td>21816.988906</td> +<td>22011.905035</td> +<td>23158.311619</td> +<td>...</td> +<td>23345.821184</td> +<td>22688.605574</td> +<td>22780.602574</td> +<td>23934.244609</td> +<td>24033.906220</td> +<td>24374.026569</td> +<td>23539.673724</td> +<td>23797.836651</td> +<td>24893.463090</td> +<td>25098.321828</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">Australia</td> +<td>2016-10-01</td> +<td>25598.929688</td> +<td>23559.919922</td> +<td>24010.281250</td> +<td>27187.578125</td> +<td>27637.937500</td> +<td>23330.804688</td> +<td>22567.948299</td> +<td>22694.449708</td> +<td>23850.068162</td> +<td>...</td> +<td>24275.423420</td> +<td>23392.040447</td> +<td>23626.165662</td> +<td>24828.207813</td> +<td>24958.926002</td> +<td>25477.951913</td> +<td>24793.436993</td> +<td>24911.271547</td> +<td>26006.244161</td> +<td>26152.362329</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">Australia</td> +<td>2017-01-01</td> +<td>26982.578125</td> +<td>24651.535156</td> +<td>25166.396484</td> +<td>28798.757812</td> +<td>29313.619141</td> +<td>24497.001953</td> +<td>23578.418503</td> +<td>23731.657437</td> +<td>25114.564017</td> +<td>...</td> +<td>25485.433879</td> +<td>24549.969625</td> +<td>24802.819691</td> +<td>26073.792872</td> +<td>26284.826386</td> +<td>26842.564741</td> +<td>26037.725561</td> +<td>26248.171831</td> +<td>27436.222761</td> +<td>27668.067666</td> +</tr> +</tbody> +</table> + +<p>5 rows Ć 21 columns</p> +</div> +</div> +</div> +</section> +<section id="plot-forecasts" class="level2"> +<h2 class="anchored" data-anchor-id="plot-forecasts">Plot forecasts</h2> +<p>Then we can plot the probabilist forecasts using the following function.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb23"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb23-1"><a href="#cb23-1" aria-hidden="true" tabindex="-1"></a>plot_df <span class="op">=</span> pd.concat([Y_df.set_index([<span class="st">'unique_id'</span>, <span class="st">'ds'</span>]), </span> +<span id="cb23-2"><a href="#cb23-2" aria-hidden="true" tabindex="-1"></a> Y_rec_df.set_index(<span class="st">'ds'</span>, append<span class="op">=</span><span class="va">True</span>)], axis<span class="op">=</span><span class="dv">1</span>)</span> +<span id="cb23-3"><a href="#cb23-3" aria-hidden="true" tabindex="-1"></a>plot_df <span class="op">=</span> plot_df.reset_index(<span class="st">'ds'</span>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<section id="plot-single-time-series" class="level3"> +<h3 class="anchored" data-anchor-id="plot-single-time-series">Plot single time series</h3> +<div class="cell"> +<div class="sourceCode cell-code" id="cb24"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb24-1"><a href="#cb24-1" aria-hidden="true" tabindex="-1"></a>hplot.plot_series(</span> +<span id="cb24-2"><a href="#cb24-2" aria-hidden="true" tabindex="-1"></a> series<span class="op">=</span><span class="st">'Australia'</span>,</span> +<span id="cb24-3"><a href="#cb24-3" aria-hidden="true" tabindex="-1"></a> Y_df<span class="op">=</span>plot_df, </span> +<span id="cb24-4"><a href="#cb24-4" aria-hidden="true" tabindex="-1"></a> models<span class="op">=</span>[<span class="st">'y'</span>, <span class="st">'AutoARIMA'</span>, </span> +<span id="cb24-5"><a href="#cb24-5" aria-hidden="true" tabindex="-1"></a> <span class="st">'AutoARIMA/MinTrace_method-ols'</span>,</span> +<span id="cb24-6"><a href="#cb24-6" aria-hidden="true" tabindex="-1"></a> <span class="st">'AutoARIMA/BottomUp'</span></span> +<span id="cb24-7"><a href="#cb24-7" aria-hidden="true" tabindex="-1"></a> ],</span> +<span id="cb24-8"><a href="#cb24-8" aria-hidden="true" tabindex="-1"></a> level<span class="op">=</span>[<span class="dv">80</span>]</span> +<span id="cb24-9"><a href="#cb24-9" aria-hidden="true" tabindex="-1"></a>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<p><img src="AustralianDomesticTourism-Permbu-Intervals_files/figure-html/cell-20-output-1.png" class="img-fluid"></p> +</div> +</div> +</section> +<section id="plot-hierarchichally-linked-time-series" class="level3"> +<h3 class="anchored" data-anchor-id="plot-hierarchichally-linked-time-series">Plot hierarchichally linked time series</h3> +<div class="cell"> +<div class="sourceCode cell-code" id="cb25"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb25-1"><a href="#cb25-1" aria-hidden="true" tabindex="-1"></a>hplot.plot_hierarchically_linked_series(</span> +<span id="cb25-2"><a href="#cb25-2" aria-hidden="true" tabindex="-1"></a> bottom_series<span class="op">=</span><span class="st">'Australia/Western Australia/Experience Perth'</span>,</span> +<span id="cb25-3"><a href="#cb25-3" aria-hidden="true" tabindex="-1"></a> Y_df<span class="op">=</span>plot_df, </span> +<span id="cb25-4"><a href="#cb25-4" aria-hidden="true" tabindex="-1"></a> models<span class="op">=</span>[<span class="st">'y'</span>, <span class="st">'AutoARIMA'</span>, <span class="st">'AutoARIMA/MinTrace_method-ols'</span>, <span class="st">'AutoARIMA/BottomUp'</span>],</span> +<span id="cb25-5"><a href="#cb25-5" aria-hidden="true" tabindex="-1"></a> level<span class="op">=</span>[<span class="dv">80</span>]</span> +<span id="cb25-6"><a href="#cb25-6" aria-hidden="true" tabindex="-1"></a>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<p><img src="AustralianDomesticTourism-Permbu-Intervals_files/figure-html/cell-21-output-1.png" class="img-fluid"></p> +</div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb26"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb26-1"><a href="#cb26-1" aria-hidden="true" tabindex="-1"></a><span class="co"># ACT only has Canberra</span></span> +<span id="cb26-2"><a href="#cb26-2" aria-hidden="true" tabindex="-1"></a>hplot.plot_hierarchically_linked_series(</span> +<span id="cb26-3"><a href="#cb26-3" aria-hidden="true" tabindex="-1"></a> bottom_series<span class="op">=</span><span class="st">'Australia/ACT/Canberra'</span>,</span> +<span id="cb26-4"><a href="#cb26-4" aria-hidden="true" tabindex="-1"></a> Y_df<span class="op">=</span>plot_df, </span> +<span id="cb26-5"><a href="#cb26-5" aria-hidden="true" tabindex="-1"></a> models<span class="op">=</span>[<span class="st">'y'</span>, <span class="st">'AutoARIMA/MinTrace_method-mint_shrink'</span>],</span> +<span id="cb26-6"><a href="#cb26-6" aria-hidden="true" tabindex="-1"></a> level<span class="op">=</span>[<span class="dv">80</span>, <span class="dv">90</span>]</span> +<span id="cb26-7"><a href="#cb26-7" aria-hidden="true" tabindex="-1"></a>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<p><img src="AustralianDomesticTourism-Permbu-Intervals_files/figure-html/cell-22-output-1.png" class="img-fluid"></p> +</div> +</div> +</section> +<section id="references" class="level3"> +<h3 class="anchored" data-anchor-id="references">References</h3> +<ul> +<li><a href="https://otexts.com/fpp3/hierarchical.html">Hyndman, R.J., & Athanasopoulos, G. (2021). āForecasting: principles and practice, 3rd edition: Chapter 11: Forecasting hierarchical and grouped series.ā. OTexts: Melbourne, Australia. OTexts.com/fpp3 Accessed on July 2022.</a></li> +<li><a href="https://robjhyndman.com/publications/mint/">Shanika L. Wickramasuriya, George Athanasopoulos, and Rob J. Hyndman. Optimal forecast reconciliation for hierarchical and grouped time series through trace minimization.Journal of the American Statistical Association, 114(526):804ā819, 2019. doi: 10.1080/01621459.2018.1448825. URL https://robjhyndman.com/publications/mint/.</a></li> +</ul> + + +</section> +</section> + +<p>If you find the code useful, please ā us on <a href="https://github.com/nixtla/hierarchicalforecast">Github</a></p></main> <!-- /main --> +<script id="quarto-html-after-body" type="application/javascript"> +window.document.addEventListener("DOMContentLoaded", function (event) { + const toggleBodyColorMode = (bsSheetEl) => { + const mode = bsSheetEl.getAttribute("data-mode"); + const bodyEl = window.document.querySelector("body"); + if (mode === "dark") { + bodyEl.classList.add("quarto-dark"); + bodyEl.classList.remove("quarto-light"); + } else { + bodyEl.classList.add("quarto-light"); + bodyEl.classList.remove("quarto-dark"); + } + } + const toggleBodyColorPrimary = () => { + const bsSheetEl = window.document.querySelector("link#quarto-bootstrap"); + if (bsSheetEl) { + toggleBodyColorMode(bsSheetEl); + } + } + toggleBodyColorPrimary(); + const icon = "ī§"; + const anchorJS = new window.AnchorJS(); + anchorJS.options = { + placement: 'right', + icon: icon + }; + anchorJS.add('.anchored'); + const isCodeAnnotation = (el) => { + for (const clz of el.classList) { + if (clz.startsWith('code-annotation-')) { + return true; + } + } + return false; + } + const clipboard = new window.ClipboardJS('.code-copy-button', { + text: function(trigger) { + const codeEl = trigger.previousElementSibling.cloneNode(true); + for (const childEl of codeEl.children) { + if (isCodeAnnotation(childEl)) { + childEl.remove(); + } + } + return codeEl.innerText; + } + }); + clipboard.on('success', function(e) { + // button target + const button = e.trigger; + // don't keep focus + button.blur(); + // flash "checked" + button.classList.add('code-copy-button-checked'); + var currentTitle = button.getAttribute("title"); + button.setAttribute("title", "Copied!"); + let tooltip; + if (window.bootstrap) { + button.setAttribute("data-bs-toggle", "tooltip"); + button.setAttribute("data-bs-placement", "left"); + button.setAttribute("data-bs-title", "Copied!"); + tooltip = new bootstrap.Tooltip(button, + { trigger: "manual", + customClass: "code-copy-button-tooltip", + offset: [0, -8]}); + tooltip.show(); + } + setTimeout(function() { + if (tooltip) { + tooltip.hide(); + button.removeAttribute("data-bs-title"); + button.removeAttribute("data-bs-toggle"); + button.removeAttribute("data-bs-placement"); + } + button.setAttribute("title", currentTitle); + button.classList.remove('code-copy-button-checked'); + }, 1000); + // clear code selection + e.clearSelection(); + }); + function tippyHover(el, contentFn) { + const config = { + allowHTML: true, + content: contentFn, + maxWidth: 500, + delay: 100, + arrow: false, + appendTo: function(el) { + return el.parentElement; + }, + interactive: true, + interactiveBorder: 10, + theme: 'quarto', + placement: 'bottom-start' + }; + window.tippy(el, config); + } + const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]'); + for (var i=0; i<noterefs.length; i++) { + const ref = noterefs[i]; + tippyHover(ref, function() { + // use id or data attribute instead here + let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href'); + try { href = new URL(href).hash; } catch {} + const id = href.replace(/^#\/?/, ""); + const note = window.document.getElementById(id); + return note.innerHTML; + }); + } + let selectedAnnoteEl; + const selectorForAnnotation = ( cell, annotation) => { + let cellAttr = 'data-code-cell="' + cell + '"'; + let lineAttr = 'data-code-annotation="' + annotation + '"'; + const selector = 'span[' + cellAttr + '][' + lineAttr + ']'; + return selector; + } + const selectCodeLines = (annoteEl) => { + const doc = window.document; + const targetCell = annoteEl.getAttribute("data-target-cell"); + const targetAnnotation = annoteEl.getAttribute("data-target-annotation"); + const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation)); + const lines = annoteSpan.getAttribute("data-code-lines").split(","); + const lineIds = lines.map((line) => { + return targetCell + "-" + line; + }) + let top = null; + let height = null; + let parent = null; + if (lineIds.length > 0) { + //compute the position of the single el (top and bottom and make a div) + const el = window.document.getElementById(lineIds[0]); + top = el.offsetTop; + height = el.offsetHeight; + parent = el.parentElement.parentElement; + if (lineIds.length > 1) { + const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]); + const bottom = lastEl.offsetTop + lastEl.offsetHeight; + height = bottom - top; + } + if (top !== null && height !== null && parent !== null) { + // cook up a div (if necessary) and position it + let div = window.document.getElementById("code-annotation-line-highlight"); + if (div === null) { + div = window.document.createElement("div"); + div.setAttribute("id", "code-annotation-line-highlight"); + div.style.position = 'absolute'; + parent.appendChild(div); + } + div.style.top = top - 2 + "px"; + div.style.height = height + 4 + "px"; + let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter"); + if (gutterDiv === null) { + gutterDiv = window.document.createElement("div"); + gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter"); + gutterDiv.style.position = 'absolute'; + const codeCell = window.document.getElementById(targetCell); + const gutter = codeCell.querySelector('.code-annotation-gutter'); + gutter.appendChild(gutterDiv); + } + gutterDiv.style.top = top - 2 + "px"; + gutterDiv.style.height = height + 4 + "px"; + } + selectedAnnoteEl = annoteEl; + } + }; + const unselectCodeLines = () => { + const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"]; + elementsIds.forEach((elId) => { + const div = window.document.getElementById(elId); + if (div) { + div.remove(); + } + }); + selectedAnnoteEl = undefined; + }; + // Attach click handler to the DT + const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); + for (const annoteDlNode of annoteDls) { + annoteDlNode.addEventListener('click', (event) => { + const clickedEl = event.target; + if (clickedEl !== selectedAnnoteEl) { + unselectCodeLines(); + const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active'); + if (activeEl) { + activeEl.classList.remove('code-annotation-active'); + } + selectCodeLines(clickedEl); + clickedEl.classList.add('code-annotation-active'); + } else { + // Unselect the line + unselectCodeLines(); + clickedEl.classList.remove('code-annotation-active'); + } + }); + } + const findCites = (el) => { + const parentEl = el.parentElement; + if (parentEl) { + const cites = parentEl.dataset.cites; + if (cites) { + return { + el, + cites: cites.split(' ') + }; + } else { + return findCites(el.parentElement) + } + } else { + return undefined; + } + }; + var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]'); + for (var i=0; i<bibliorefs.length; i++) { + const ref = bibliorefs[i]; + const citeInfo = findCites(ref); + if (citeInfo) { + tippyHover(citeInfo.el, function() { + var popup = window.document.createElement('div'); + citeInfo.cites.forEach(function(cite) { + var citeDiv = window.document.createElement('div'); + citeDiv.classList.add('hanging-indent'); + citeDiv.classList.add('csl-entry'); + var biblioDiv = window.document.getElementById('ref-' + cite); + if (biblioDiv) { + citeDiv.innerHTML = biblioDiv.innerHTML; + } + popup.appendChild(citeDiv); + }); + return popup.innerHTML; + }); + } + } +}); +</script> +</div> <!-- /content --> + + + +</body></html> \ No newline at end of file diff --git a/examples/australiandomestictourism.html b/examples/australiandomestictourism.html new file mode 100644 index 00000000..a8670447 --- /dev/null +++ b/examples/australiandomestictourism.html @@ -0,0 +1,1294 @@ +<!DOCTYPE html> +<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head> + +<meta charset="utf-8"> +<meta name="generator" content="quarto-1.3.450"> + +<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes"> + +<meta name="description" content="Geographical Hierarchical Forecasting on Australian Tourism Data"> + +<title>hierarchicalforecast - Geographical Aggregation (Tourism)</title> +<style> +code{white-space: pre-wrap;} +span.smallcaps{font-variant: small-caps;} +div.columns{display: flex; gap: min(4vw, 1.5em);} +div.column{flex: auto; overflow-x: auto;} +div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;} +ul.task-list{list-style: none;} +ul.task-list li input[type="checkbox"] { + width: 0.8em; + margin: 0 0.8em 0.2em -1em; /* quarto-specific, see https://github.com/quarto-dev/quarto-cli/issues/4556 */ + vertical-align: middle; +} +/* CSS for syntax highlighting */ +pre > code.sourceCode { white-space: pre; position: relative; } +pre > code.sourceCode > span { display: inline-block; line-height: 1.25; } +pre > code.sourceCode > span:empty { height: 1.2em; } +.sourceCode { overflow: visible; } +code.sourceCode > span { color: inherit; text-decoration: inherit; } +div.sourceCode { margin: 1em 0; } +pre.sourceCode { margin: 0; } +@media screen { +div.sourceCode { overflow: auto; } +} +@media print { +pre > code.sourceCode { white-space: pre-wrap; } +pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; } +} +pre.numberSource code + { counter-reset: source-line 0; } +pre.numberSource code > span + { position: relative; left: -4em; counter-increment: source-line; } +pre.numberSource code > span > a:first-child::before + { content: counter(source-line); + position: relative; left: -1em; text-align: right; vertical-align: baseline; + border: none; display: inline-block; + -webkit-touch-callout: none; -webkit-user-select: none; + -khtml-user-select: none; -moz-user-select: none; + -ms-user-select: none; user-select: none; + padding: 0 4px; width: 4em; + } +pre.numberSource { margin-left: 3em; padding-left: 4px; } +div.sourceCode + { } +@media screen { +pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; } +} +</style> + + +<script src="../site_libs/quarto-nav/quarto-nav.js"></script> +<script src="../site_libs/quarto-nav/headroom.min.js"></script> +<script src="../site_libs/clipboard/clipboard.min.js"></script> +<script src="../site_libs/quarto-search/autocomplete.umd.js"></script> +<script src="../site_libs/quarto-search/fuse.min.js"></script> +<script src="../site_libs/quarto-search/quarto-search.js"></script> +<meta name="quarto:offset" content="../"> +<link href="../favicon_png.png" rel="icon" type="image/png"> +<script src="../site_libs/quarto-html/quarto.js"></script> +<script src="../site_libs/quarto-html/popper.min.js"></script> +<script src="../site_libs/quarto-html/tippy.umd.min.js"></script> +<script src="../site_libs/quarto-html/anchor.min.js"></script> +<link href="../site_libs/quarto-html/tippy.css" rel="stylesheet"> +<link href="../site_libs/quarto-html/quarto-syntax-highlighting.css" rel="stylesheet" id="quarto-text-highlighting-styles"> +<script src="../site_libs/bootstrap/bootstrap.min.js"></script> +<link href="../site_libs/bootstrap/bootstrap-icons.css" rel="stylesheet"> +<link href="../site_libs/bootstrap/bootstrap.min.css" rel="stylesheet" id="quarto-bootstrap" data-mode="light"> +<script id="quarto-search-options" type="application/json">{ + "location": "navbar", + "copy-button": false, + "collapse-after": 3, + "panel-placement": "end", + "type": "overlay", + "limit": 20, + "language": { + "search-no-results-text": "No results", + "search-matching-documents-text": "matching documents", + "search-copy-link-title": "Copy link to search", + "search-hide-matches-text": "Hide additional matches", + "search-more-match-text": "more match in this document", + "search-more-matches-text": "more matches in this document", + "search-clear-button-title": "Clear", + "search-detached-cancel-button-title": "Cancel", + "search-submit-button-title": "Submit", + "search-label": "Search" + } +}</script> +<script async="" src="https://www.googletagmanager.com/gtag/js?id=G-NXJNCVR18L"></script> + +<script type="text/javascript"> + +window.dataLayer = window.dataLayer || []; +function gtag(){dataLayer.push(arguments);} +gtag('js', new Date()); +gtag('config', 'G-NXJNCVR18L', { 'anonymize_ip': true}); +</script> +<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js" integrity="sha512-c3Nl8+7g4LMSTdrm621y7kf9v3SDPnhxLNhcjFJbKECVnmZHTdo+IRO05sNLTH/D3vA6u1X32ehoLC7WFVdheg==" crossorigin="anonymous"></script> +<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js" integrity="sha512-bLT0Qm9VnAYZDflyKcBaQ2gg0hSYNQrJ8RilYldYQ1FxQYoCLtUjuuRuZo+fjqhx/qtq/1itJ0C2ejDxltZVFg==" crossorigin="anonymous"></script> +<script type="application/javascript">define('jquery', [],function() {return window.jQuery;})</script> + + +<link rel="stylesheet" href="../styles.css"> +<meta property="og:title" content="hierarchicalforecast - Geographical Aggregation (Tourism)"> +<meta property="og:description" content="Geographical Hierarchical Forecasting on Australian Tourism Data"> +<meta property="og:image" content="https://colab.research.google.com/assets/colab-badge.svg"> +<meta property="og:site-name" content="hierarchicalforecast"> +<meta name="twitter:title" content="hierarchicalforecast - Geographical Aggregation (Tourism)"> +<meta name="twitter:description" content="Geographical Hierarchical Forecasting on Australian Tourism Data"> +<meta name="twitter:image" content="https://colab.research.google.com/assets/colab-badge.svg"> +<meta name="twitter:card" content="summary_large_image"> +</head> + +<body class="nav-sidebar floating nav-fixed"> + +<div id="quarto-search-results"></div> + <header id="quarto-header" class="headroom fixed-top"> + <nav class="navbar navbar-expand-lg navbar-dark "> + <div class="navbar-container container-fluid"> + <div class="navbar-brand-container"> + <a class="navbar-brand" href="../index.html"> + <span class="navbar-title">hierarchicalforecast</span> + </a> + </div> + <div id="quarto-search" class="" title="Search"></div> + <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + <span class="navbar-toggler-icon"></span> +</button> + <div class="collapse navbar-collapse" id="navbarCollapse"> + <ul class="navbar-nav navbar-nav-scroll me-auto"> + <li class="nav-item"> + <a class="nav-link active" href="../examples/tourismsmall.html" rel="" target="" aria-current="page"> + <span class="menu-text">Get Started</span></a> + </li> + <li class="nav-item dropdown "> + <a class="nav-link dropdown-toggle" href="#" id="nav-menu-nixtlaverse" role="button" data-bs-toggle="dropdown" aria-expanded="false" rel="" target=""> + <span class="menu-text">NixtlaVerse</span> + </a> + <ul class="dropdown-menu" aria-labelledby="nav-menu-nixtlaverse"> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/mlforecast" rel="" target=""> + <span class="dropdown-text">MLForecast š¤</span></a> + </li> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/neuralforecast" rel="" target=""> + <span class="dropdown-text">NeuralForecast š§ </span></a> + </li> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/statsforecast" rel="" target=""> + <span class="dropdown-text">StatsForecast ā”ļø</span></a> + </li> + </ul> + </li> + <li class="nav-item dropdown "> + <a class="nav-link dropdown-toggle" href="#" id="nav-menu-help" role="button" data-bs-toggle="dropdown" aria-expanded="false" rel="" target=""> + <span class="menu-text">Help</span> + </a> + <ul class="dropdown-menu" aria-labelledby="nav-menu-help"> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/hierarchicalforecast/issues/new/choose" rel="" target=""><i class="bi bi-bug" role="img"> +</i> + <span class="dropdown-text">Report an Issue</span></a> + </li> + <li> + <a class="dropdown-item" href="https://join.slack.com/t/nixtlacommunity/shared_invite/zt-1kd5m5db7-7OOfy0xVNf1PcvCiAPWvPw" rel="" target=""><i class="bi bi-chat-right-text" role="img"> +</i> + <span class="dropdown-text">Join our Slack</span></a> + </li> + </ul> + </li> +</ul> + <ul class="navbar-nav navbar-nav-scroll ms-auto"> + <li class="nav-item compact"> + <a class="nav-link" href="https://github.com/nixtla/hierarchicalforecast" rel="" target=""><i class="bi bi-github" role="img"> +</i> + <span class="menu-text"></span></a> + </li> + <li class="nav-item compact"> + <a class="nav-link" href="https://twitter.com/nixtlainc" rel="" target=""><i class="bi bi-twitter" role="img" aria-label="Nixtla Twitter"> +</i> + <span class="menu-text"></span></a> + </li> +</ul> + <div class="quarto-navbar-tools"> +</div> + </div> <!-- /navcollapse --> + </div> <!-- /container-fluid --> + </nav> + <nav class="quarto-secondary-nav"> + <div class="container-fluid d-flex"> + <button type="button" class="quarto-btn-toggle btn" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + <i class="bi bi-layout-text-sidebar-reverse"></i> + </button> + <nav class="quarto-page-breadcrumbs" aria-label="breadcrumb"><ol class="breadcrumb"><li class="breadcrumb-item">Tutorials</li><li class="breadcrumb-item"><a href="../examples/australiandomestictourism.html">Point Reconciliation</a></li><li class="breadcrumb-item"><a href="../examples/australiandomestictourism.html">Geographical Aggregation (Tourism)</a></li></ol></nav> + <a class="flex-grow-1" role="button" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + </a> + </div> + </nav> +</header> +<!-- content --> +<div id="quarto-content" class="quarto-container page-columns page-rows-contents page-layout-article page-navbar"> +<!-- sidebar --> + <nav id="quarto-sidebar" class="sidebar collapse collapse-horizontal sidebar-navigation floating overflow-auto"> + <div class="sidebar-menu-container"> + <ul class="list-unstyled mt-1"> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../index.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Hierarchical Forecast š</span></a> + </div> +</li> + <li class="px-0"><hr class="sidebar-divider hi "></li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-1" aria-expanded="false"> + <span class="menu-text">Getting Started</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-1" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-1" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/installation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Install</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/tourismsmall.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Reconciliation Quick Start</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/introduction.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Introduction</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-2" aria-expanded="true"> + <span class="menu-text">Tutorials</span></a> + <a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-2" aria-expanded="true" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-2" class="collapse list-unstyled sidebar-section depth1 show"> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-3" aria-expanded="true"> + <span class="menu-text">Point Reconciliation</span></a> + <a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-3" aria-expanded="true" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-3" class="collapse list-unstyled sidebar-section depth2 show"> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism.html" class="sidebar-item-text sidebar-link active"> + <span class="menu-text">Geographical Aggregation (Tourism)</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australianprisonpopulation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Geographical Aggregation (Prison Population)</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/nonnegativereconciliation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Non-Negative MinTrace</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-4" aria-expanded="false"> + <span class="menu-text">Probabilistic Reconciliation</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-4" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-4" class="collapse list-unstyled sidebar-section depth2 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Normality</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism-bootstraped-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Bootstrap</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism-permbu-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">PERMBU</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/tourismlarge-evaluation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Probabilistic Forecast Evaluation</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-5" aria-expanded="false"> + <span class="menu-text">ML Forecast Reconciliation</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-5" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-5" class="collapse list-unstyled sidebar-section depth2 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/hierarchicalforecast-gluonts.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">GluonTS</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/mlframeworksexample.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Neural/MLForecast</span></a> + </div> +</li> + </ul> + </li> + </ul> + </li> + <li class="sidebar-item"> + <span class="menu-text">Methods</span> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-6" aria-expanded="false"> + <span class="menu-text">API Reference</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-6" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-6" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../core.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Core </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../methods.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Reconciliation Methods </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../probabilistic_methods.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Probabilistic Methods </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../evaluation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Hierarchical Evaluation</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../utils.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Aggregation/Visualization Utils</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-7" aria-expanded="false"> + <span class="menu-text">Community</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-7" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-7" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item"> + <span class="menu-text">Contributing</span> + </li> + </ul> + </li> + </ul> + </div> +</nav> +<div id="quarto-sidebar-glass" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass"></div> +<!-- margin-sidebar --> + <div id="quarto-margin-sidebar" class="sidebar margin-sidebar"> + <nav id="TOC" role="doc-toc" class="toc-active"> + <h2 id="toc-title">On this page</h2> + + <ul> + <li><a href="#load-and-process-data" id="toc-load-and-process-data" class="nav-link active" data-scroll-target="#load-and-process-data">1. Load and Process Data</a> + <ul class="collapse"> + <li><a href="#split-traintest-sets" id="toc-split-traintest-sets" class="nav-link" data-scroll-target="#split-traintest-sets">Split Train/Test sets</a></li> + </ul></li> + <li><a href="#computing-base-forecasts" id="toc-computing-base-forecasts" class="nav-link" data-scroll-target="#computing-base-forecasts">2. Computing base forecasts</a></li> + <li><a href="#reconcile-forecasts" id="toc-reconcile-forecasts" class="nav-link" data-scroll-target="#reconcile-forecasts">3. Reconcile forecasts</a></li> + <li><a href="#evaluation" id="toc-evaluation" class="nav-link" data-scroll-target="#evaluation">4. Evaluation</a> + <ul class="collapse"> + <li><a href="#rmse" id="toc-rmse" class="nav-link" data-scroll-target="#rmse">RMSE</a></li> + <li><a href="#mase" id="toc-mase" class="nav-link" data-scroll-target="#mase">MASE</a></li> + <li><a href="#comparison-fable" id="toc-comparison-fable" class="nav-link" data-scroll-target="#comparison-fable">Comparison fable</a></li> + <li><a href="#references" id="toc-references" class="nav-link" data-scroll-target="#references">References</a></li> + </ul></li> + </ul> +<div class="toc-actions"><div><i class="bi bi-github"></i></div><div class="action-links"><p><a href="https://github.com/Nixtla/hierarchicalforecast/issues/new" class="toc-action">Report an issue</a></p></div></div></nav> + </div> +<!-- main --> +<main class="content" id="quarto-document-content"> + +<header id="title-block-header" class="quarto-title-block default"> +<div class="quarto-title"> +<h1 class="title">Geographical Aggregation (Tourism)</h1> +</div> + +<div> + <div class="description"> + Geographical Hierarchical Forecasting on Australian Tourism Data + </div> +</div> + + +<div class="quarto-title-meta"> + + + + + </div> + + +</header> + +<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! --> +<p>In many applications, a set of time series is hierarchically organized. Examples include the presence of geographic levels, products, or categories that define different types of aggregations. In such scenarios, forecasters are often required to provide predictions for all disaggregate and aggregate series. A natural desire is for those predictions to be <strong>ācoherentā</strong>, that is, for the bottom series to add up precisely to the forecasts of the aggregated series.</p> +<p>In this notebook we present an example on how to use <code>HierarchicalForecast</code> to produce coherent forecasts between geographical levels. We will use the classic Australian Domestic Tourism (<code>Tourism</code>) dataset, which contains monthly time series of the number of visitors to each state of Australia.</p> +<p>We will first load the <code>Tourism</code> data and produce base forecasts using an <code>ETS</code> model from <code>StatsForecast</code>, and then reconciliate the forecasts with several reconciliation algorithms from <code>HierarchicalForecast</code>. Finally, we show the performance is comparable with the results reported by the <a href="https://otexts.com/fpp3/tourism.html">Forecasting: Principles and Practice</a> which uses the R package <a href="https://github.com/tidyverts/fable">fable</a>.</p> +<p>You can run these experiments using CPU or GPU with Google Colab.</p> +<p><a href="https://colab.research.google.com/github/Nixtla/hierarchicalforecast/blob/main/nbs/examples/AustralianDomesticTourism.ipynb" target="_parent"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"></a></p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb1"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="op">!</span>pip install hierarchicalforecast</span> +<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="op">!</span>pip install <span class="op">-</span>U statsforecast numba</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<section id="load-and-process-data" class="level2"> +<h2 class="anchored" data-anchor-id="load-and-process-data">1. Load and Process Data</h2> +<p>In this example we will use the <a href="https://otexts.com/fpp3/tourism.html">Tourism</a> dataset from the <a href="https://otexts.com/fpp3/">Forecasting: Principles and Practice</a> book.</p> +<p>The dataset only contains the time series at the lowest level, so we need to create the time series for all hierarchies.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb2"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> numpy <span class="im">as</span> np</span> +<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> pandas <span class="im">as</span> pd</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb3"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a>Y_df <span class="op">=</span> pd.read_csv(<span class="st">'https://raw.githubusercontent.com/Nixtla/transfer-learning-time-series/main/datasets/tourism.csv'</span>)</span> +<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>Y_df <span class="op">=</span> Y_df.rename({<span class="st">'Trips'</span>: <span class="st">'y'</span>, <span class="st">'Quarter'</span>: <span class="st">'ds'</span>}, axis<span class="op">=</span><span class="dv">1</span>)</span> +<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>Y_df.insert(<span class="dv">0</span>, <span class="st">'Country'</span>, <span class="st">'Australia'</span>)</span> +<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>Y_df <span class="op">=</span> Y_df[[<span class="st">'Country'</span>, <span class="st">'Region'</span>, <span class="st">'State'</span>, <span class="st">'Purpose'</span>, <span class="st">'ds'</span>, <span class="st">'y'</span>]]</span> +<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>Y_df[<span class="st">'ds'</span>] <span class="op">=</span> Y_df[<span class="st">'ds'</span>].<span class="bu">str</span>.replace(<span class="vs">r'(\d+) (Q\d)'</span>, <span class="vs">r'\1-\2'</span>, regex<span class="op">=</span><span class="va">True</span>)</span> +<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>Y_df[<span class="st">'ds'</span>] <span class="op">=</span> pd.to_datetime(Y_df[<span class="st">'ds'</span>])</span> +<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a>Y_df.head()</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<div> + + +<table class="dataframe table table-sm table-striped small" data-quarto-postprocess="true" data-border="1"> +<thead> +<tr class="header"> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th">Country</th> +<th data-quarto-table-cell-role="th">Region</th> +<th data-quarto-table-cell-role="th">State</th> +<th data-quarto-table-cell-role="th">Purpose</th> +<th data-quarto-table-cell-role="th">ds</th> +<th data-quarto-table-cell-role="th">y</th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td data-quarto-table-cell-role="th">0</td> +<td>Australia</td> +<td>Adelaide</td> +<td>South Australia</td> +<td>Business</td> +<td>1998-01-01</td> +<td>135.077690</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">1</td> +<td>Australia</td> +<td>Adelaide</td> +<td>South Australia</td> +<td>Business</td> +<td>1998-04-01</td> +<td>109.987316</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">2</td> +<td>Australia</td> +<td>Adelaide</td> +<td>South Australia</td> +<td>Business</td> +<td>1998-07-01</td> +<td>166.034687</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">3</td> +<td>Australia</td> +<td>Adelaide</td> +<td>South Australia</td> +<td>Business</td> +<td>1998-10-01</td> +<td>127.160464</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">4</td> +<td>Australia</td> +<td>Adelaide</td> +<td>South Australia</td> +<td>Business</td> +<td>1999-01-01</td> +<td>137.448533</td> +</tr> +</tbody> +</table> + +</div> +</div> +</div> +<p>The dataset can be grouped in the following non-strictly hierarchical structure.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb4"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a>spec <span class="op">=</span> [</span> +<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a> [<span class="st">'Country'</span>],</span> +<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a> [<span class="st">'Country'</span>, <span class="st">'State'</span>], </span> +<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a> [<span class="st">'Country'</span>, <span class="st">'Purpose'</span>], </span> +<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a> [<span class="st">'Country'</span>, <span class="st">'State'</span>, <span class="st">'Region'</span>], </span> +<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a> [<span class="st">'Country'</span>, <span class="st">'State'</span>, <span class="st">'Purpose'</span>], </span> +<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a> [<span class="st">'Country'</span>, <span class="st">'State'</span>, <span class="st">'Region'</span>, <span class="st">'Purpose'</span>]</span> +<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a>]</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<p>Using the <a href="https://Nixtla.github.io/hierarchicalforecast/utils.html#aggregate"><code>aggregate</code></a> function from <code>HierarchicalForecast</code> we can get the full set of time series.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb5"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> hierarchicalforecast.utils <span class="im">import</span> aggregate</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb6"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a>Y_df, S_df, tags <span class="op">=</span> aggregate(Y_df, spec)</span> +<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>Y_df <span class="op">=</span> Y_df.reset_index()</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb7"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a>Y_df.head()</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<div> + + +<table class="dataframe table table-sm table-striped small" data-quarto-postprocess="true" data-border="1"> +<thead> +<tr class="header"> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th">unique_id</th> +<th data-quarto-table-cell-role="th">ds</th> +<th data-quarto-table-cell-role="th">y</th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td data-quarto-table-cell-role="th">0</td> +<td>Australia</td> +<td>1998-01-01</td> +<td>23182.197269</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">1</td> +<td>Australia</td> +<td>1998-04-01</td> +<td>20323.380067</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">2</td> +<td>Australia</td> +<td>1998-07-01</td> +<td>19826.640511</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">3</td> +<td>Australia</td> +<td>1998-10-01</td> +<td>20830.129891</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">4</td> +<td>Australia</td> +<td>1999-01-01</td> +<td>22087.353380</td> +</tr> +</tbody> +</table> + +</div> +</div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb8"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a>S_df.iloc[:<span class="dv">5</span>, :<span class="dv">5</span>]</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<div> + + +<table class="dataframe table table-sm table-striped small" data-quarto-postprocess="true" data-border="1"> +<thead> +<tr class="header"> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th">Australia/ACT/Canberra/Business</th> +<th data-quarto-table-cell-role="th">Australia/ACT/Canberra/Holiday</th> +<th data-quarto-table-cell-role="th">Australia/ACT/Canberra/Other</th> +<th data-quarto-table-cell-role="th">Australia/ACT/Canberra/Visiting</th> +<th data-quarto-table-cell-role="th">Australia/New South Wales/Blue Mountains/Business</th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td data-quarto-table-cell-role="th">Australia</td> +<td>1.0</td> +<td>1.0</td> +<td>1.0</td> +<td>1.0</td> +<td>1.0</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">Australia/ACT</td> +<td>1.0</td> +<td>1.0</td> +<td>1.0</td> +<td>1.0</td> +<td>0.0</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">Australia/New South Wales</td> +<td>0.0</td> +<td>0.0</td> +<td>0.0</td> +<td>0.0</td> +<td>1.0</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">Australia/Northern Territory</td> +<td>0.0</td> +<td>0.0</td> +<td>0.0</td> +<td>0.0</td> +<td>0.0</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">Australia/Queensland</td> +<td>0.0</td> +<td>0.0</td> +<td>0.0</td> +<td>0.0</td> +<td>0.0</td> +</tr> +</tbody> +</table> + +</div> +</div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb9"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a>tags[<span class="st">'Country/Purpose'</span>]</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<pre><code>array(['Australia/Business', 'Australia/Holiday', 'Australia/Other', + 'Australia/Visiting'], dtype=object)</code></pre> +</div> +</div> +<section id="split-traintest-sets" class="level3"> +<h3 class="anchored" data-anchor-id="split-traintest-sets">Split Train/Test sets</h3> +<p>We use the final two years (8 quarters) as test set.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb11"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a>Y_test_df <span class="op">=</span> Y_df.groupby(<span class="st">'unique_id'</span>).tail(<span class="dv">8</span>)</span> +<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a>Y_train_df <span class="op">=</span> Y_df.drop(Y_test_df.index)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb12"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a>Y_test_df <span class="op">=</span> Y_test_df.set_index(<span class="st">'unique_id'</span>)</span> +<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a>Y_train_df <span class="op">=</span> Y_train_df.set_index(<span class="st">'unique_id'</span>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb13"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a>Y_train_df.groupby(<span class="st">'unique_id'</span>).size()</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<pre><code>unique_id +Australia 72 +Australia/ACT 72 +Australia/ACT/Business 72 +Australia/ACT/Canberra 72 +Australia/ACT/Canberra/Business 72 + .. +Australia/Western Australia/Experience Perth/Other 72 +Australia/Western Australia/Experience Perth/Visiting 72 +Australia/Western Australia/Holiday 72 +Australia/Western Australia/Other 72 +Australia/Western Australia/Visiting 72 +Length: 425, dtype: int64</code></pre> +</div> +</div> +</section> +</section> +<section id="computing-base-forecasts" class="level2"> +<h2 class="anchored" data-anchor-id="computing-base-forecasts">2. Computing base forecasts</h2> +<p>The following cell computes the <strong>base forecasts</strong> for each time series in <code>Y_df</code> using the <code>ETS</code> model. Observe that <code>Y_hat_df</code> contains the forecasts but they are not coherent.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb15"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> statsforecast.models <span class="im">import</span> ETS</span> +<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> statsforecast.core <span class="im">import</span> StatsForecast</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb16"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a>fcst <span class="op">=</span> StatsForecast(df<span class="op">=</span>Y_train_df, </span> +<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a> models<span class="op">=</span>[ETS(season_length<span class="op">=</span><span class="dv">4</span>, model<span class="op">=</span><span class="st">'ZZA'</span>)], </span> +<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a> freq<span class="op">=</span><span class="st">'QS'</span>, n_jobs<span class="op">=-</span><span class="dv">1</span>)</span> +<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a>Y_hat_df <span class="op">=</span> fcst.forecast(h<span class="op">=</span><span class="dv">8</span>, fitted<span class="op">=</span><span class="va">True</span>)</span> +<span id="cb16-5"><a href="#cb16-5" aria-hidden="true" tabindex="-1"></a>Y_fitted_df <span class="op">=</span> fcst.forecast_fitted_values()</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +</section> +<section id="reconcile-forecasts" class="level2"> +<h2 class="anchored" data-anchor-id="reconcile-forecasts">3. Reconcile forecasts</h2> +<p>The following cell makes the previous forecasts coherent using the <a href="https://Nixtla.github.io/hierarchicalforecast/core.html#hierarchicalreconciliation"><code>HierarchicalReconciliation</code></a> class. Since the hierarchy structure is not strict, we canāt use methods such as <a href="https://Nixtla.github.io/hierarchicalforecast/methods.html#topdown"><code>TopDown</code></a> or <a href="https://Nixtla.github.io/hierarchicalforecast/methods.html#middleout"><code>MiddleOut</code></a>. In this example we use <a href="https://Nixtla.github.io/hierarchicalforecast/methods.html#bottomup"><code>BottomUp</code></a> and <a href="https://Nixtla.github.io/hierarchicalforecast/methods.html#mintrace"><code>MinTrace</code></a>.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb17"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> hierarchicalforecast.methods <span class="im">import</span> BottomUp, MinTrace</span> +<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> hierarchicalforecast.core <span class="im">import</span> HierarchicalReconciliation</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb18"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a>reconcilers <span class="op">=</span> [</span> +<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a> BottomUp(),</span> +<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a> MinTrace(method<span class="op">=</span><span class="st">'mint_shrink'</span>),</span> +<span id="cb18-4"><a href="#cb18-4" aria-hidden="true" tabindex="-1"></a> MinTrace(method<span class="op">=</span><span class="st">'ols'</span>)</span> +<span id="cb18-5"><a href="#cb18-5" aria-hidden="true" tabindex="-1"></a>]</span> +<span id="cb18-6"><a href="#cb18-6" aria-hidden="true" tabindex="-1"></a>hrec <span class="op">=</span> HierarchicalReconciliation(reconcilers<span class="op">=</span>reconcilers)</span> +<span id="cb18-7"><a href="#cb18-7" aria-hidden="true" tabindex="-1"></a>Y_rec_df <span class="op">=</span> hrec.reconcile(Y_hat_df<span class="op">=</span>Y_hat_df, Y_df<span class="op">=</span>Y_fitted_df, S<span class="op">=</span>S_df, tags<span class="op">=</span>tags)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<p>The dataframe <code>Y_rec_df</code> contains the reconciled forecasts.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb19"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a>Y_rec_df.head()</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<div> + + +<table class="dataframe table table-sm table-striped small" data-quarto-postprocess="true" data-border="1"> +<thead> +<tr class="header"> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th">ds</th> +<th data-quarto-table-cell-role="th">ETS</th> +<th data-quarto-table-cell-role="th">ETS/BottomUp</th> +<th data-quarto-table-cell-role="th">ETS/MinTrace_method-mint_shrink</th> +<th data-quarto-table-cell-role="th">ETS/MinTrace_method-ols</th> +</tr> +<tr class="odd"> +<th data-quarto-table-cell-role="th">unique_id</th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td data-quarto-table-cell-role="th">Australia</td> +<td>2016-01-01</td> +<td>25990.068359</td> +<td>24379.679688</td> +<td>25438.888351</td> +<td>25894.418893</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">Australia</td> +<td>2016-04-01</td> +<td>24458.490234</td> +<td>22902.664062</td> +<td>23925.188541</td> +<td>24357.230480</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">Australia</td> +<td>2016-07-01</td> +<td>23974.056641</td> +<td>22412.984375</td> +<td>23440.310338</td> +<td>23865.929521</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">Australia</td> +<td>2016-10-01</td> +<td>24563.455078</td> +<td>23127.638672</td> +<td>24101.001833</td> +<td>24470.783968</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">Australia</td> +<td>2017-01-01</td> +<td>25990.068359</td> +<td>24516.175781</td> +<td>25556.667616</td> +<td>25901.382401</td> +</tr> +</tbody> +</table> + +</div> +</div> +</div> +</section> +<section id="evaluation" class="level2"> +<h2 class="anchored" data-anchor-id="evaluation">4. Evaluation</h2> +<p>The <code>HierarchicalForecast</code> package includes the <a href="https://Nixtla.github.io/hierarchicalforecast/evaluation.html#hierarchicalevaluation"><code>HierarchicalEvaluation</code></a> class to evaluate the different hierarchies and also is capable of compute scaled metrics compared to a benchmark model.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb20"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb20-1"><a href="#cb20-1" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> hierarchicalforecast.evaluation <span class="im">import</span> HierarchicalEvaluation</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb21"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb21-1"><a href="#cb21-1" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> rmse(y, y_hat):</span> +<span id="cb21-2"><a href="#cb21-2" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> np.mean(np.sqrt(np.mean((y<span class="op">-</span>y_hat)<span class="op">**</span><span class="dv">2</span>, axis<span class="op">=</span><span class="dv">1</span>)))</span> +<span id="cb21-3"><a href="#cb21-3" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb21-4"><a href="#cb21-4" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> mase(y, y_hat, y_insample, seasonality<span class="op">=</span><span class="dv">4</span>):</span> +<span id="cb21-5"><a href="#cb21-5" aria-hidden="true" tabindex="-1"></a> errors <span class="op">=</span> np.mean(np.<span class="bu">abs</span>(y <span class="op">-</span> y_hat), axis<span class="op">=</span><span class="dv">1</span>)</span> +<span id="cb21-6"><a href="#cb21-6" aria-hidden="true" tabindex="-1"></a> scale <span class="op">=</span> np.mean(np.<span class="bu">abs</span>(y_insample[:, seasonality:] <span class="op">-</span> y_insample[:, :<span class="op">-</span>seasonality]), axis<span class="op">=</span><span class="dv">1</span>)</span> +<span id="cb21-7"><a href="#cb21-7" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> np.mean(errors <span class="op">/</span> scale)</span> +<span id="cb21-8"><a href="#cb21-8" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb21-9"><a href="#cb21-9" aria-hidden="true" tabindex="-1"></a>eval_tags <span class="op">=</span> {}</span> +<span id="cb21-10"><a href="#cb21-10" aria-hidden="true" tabindex="-1"></a>eval_tags[<span class="st">'Total'</span>] <span class="op">=</span> tags[<span class="st">'Country'</span>]</span> +<span id="cb21-11"><a href="#cb21-11" aria-hidden="true" tabindex="-1"></a>eval_tags[<span class="st">'Purpose'</span>] <span class="op">=</span> tags[<span class="st">'Country/Purpose'</span>]</span> +<span id="cb21-12"><a href="#cb21-12" aria-hidden="true" tabindex="-1"></a>eval_tags[<span class="st">'State'</span>] <span class="op">=</span> tags[<span class="st">'Country/State'</span>]</span> +<span id="cb21-13"><a href="#cb21-13" aria-hidden="true" tabindex="-1"></a>eval_tags[<span class="st">'Regions'</span>] <span class="op">=</span> tags[<span class="st">'Country/State/Region'</span>]</span> +<span id="cb21-14"><a href="#cb21-14" aria-hidden="true" tabindex="-1"></a>eval_tags[<span class="st">'Bottom'</span>] <span class="op">=</span> tags[<span class="st">'Country/State/Region/Purpose'</span>]</span> +<span id="cb21-15"><a href="#cb21-15" aria-hidden="true" tabindex="-1"></a>eval_tags[<span class="st">'All'</span>] <span class="op">=</span> np.concatenate(<span class="bu">list</span>(tags.values()))</span> +<span id="cb21-16"><a href="#cb21-16" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb21-17"><a href="#cb21-17" aria-hidden="true" tabindex="-1"></a>evaluator <span class="op">=</span> HierarchicalEvaluation(evaluators<span class="op">=</span>[rmse, mase])</span> +<span id="cb21-18"><a href="#cb21-18" aria-hidden="true" tabindex="-1"></a>evaluation <span class="op">=</span> evaluator.evaluate(</span> +<span id="cb21-19"><a href="#cb21-19" aria-hidden="true" tabindex="-1"></a> Y_hat_df<span class="op">=</span>Y_rec_df, Y_test_df<span class="op">=</span>Y_test_df,</span> +<span id="cb21-20"><a href="#cb21-20" aria-hidden="true" tabindex="-1"></a> tags<span class="op">=</span>eval_tags, Y_df<span class="op">=</span>Y_train_df</span> +<span id="cb21-21"><a href="#cb21-21" aria-hidden="true" tabindex="-1"></a>)</span> +<span id="cb21-22"><a href="#cb21-22" aria-hidden="true" tabindex="-1"></a>evaluation <span class="op">=</span> evaluation.drop(<span class="st">'Overall'</span>)</span> +<span id="cb21-23"><a href="#cb21-23" aria-hidden="true" tabindex="-1"></a>evaluation.columns <span class="op">=</span> [<span class="st">'Base'</span>, <span class="st">'BottomUp'</span>, <span class="st">'MinTrace(mint_shrink)'</span>, <span class="st">'MinTrace(ols)'</span>]</span> +<span id="cb21-24"><a href="#cb21-24" aria-hidden="true" tabindex="-1"></a>evaluation <span class="op">=</span> evaluation.applymap(<span class="st">'</span><span class="sc">{:.2f}</span><span class="st">'</span>.<span class="bu">format</span>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-stderr"> +<pre><code>/var/folders/rp/97y9_3ns23v01hdn0rp9ndw40000gp/T/ipykernel_46857/2768439279.py:22: PerformanceWarning: dropping on a non-lexsorted multi-index without a level parameter may impact performance. + evaluation = evaluation.drop('Overall')</code></pre> +</div> +</div> +<section id="rmse" class="level3"> +<h3 class="anchored" data-anchor-id="rmse">RMSE</h3> +<p>The following table shows the performance measured using RMSE across levels for each reconciliation method.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb23"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb23-1"><a href="#cb23-1" aria-hidden="true" tabindex="-1"></a>evaluation.query(<span class="st">'metric == "rmse"'</span>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<div> + + +<table class="dataframe table table-sm table-striped small" data-quarto-postprocess="true" data-border="1"> +<thead> +<tr class="header"> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th">Base</th> +<th data-quarto-table-cell-role="th">BottomUp</th> +<th data-quarto-table-cell-role="th">MinTrace(mint_shrink)</th> +<th data-quarto-table-cell-role="th">MinTrace(ols)</th> +</tr> +<tr class="odd"> +<th data-quarto-table-cell-role="th">level</th> +<th data-quarto-table-cell-role="th">metric</th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td data-quarto-table-cell-role="th">Total</td> +<td data-quarto-table-cell-role="th">rmse</td> +<td>1743.29</td> +<td>3028.93</td> +<td>2102.47</td> +<td>1818.94</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">Purpose</td> +<td data-quarto-table-cell-role="th">rmse</td> +<td>534.75</td> +<td>791.28</td> +<td>574.84</td> +<td>515.53</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">State</td> +<td data-quarto-table-cell-role="th">rmse</td> +<td>308.15</td> +<td>413.43</td> +<td>315.89</td> +<td>287.34</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">Regions</td> +<td data-quarto-table-cell-role="th">rmse</td> +<td>51.65</td> +<td>55.14</td> +<td>46.48</td> +<td>46.29</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">Bottom</td> +<td data-quarto-table-cell-role="th">rmse</td> +<td>19.37</td> +<td>19.37</td> +<td>17.78</td> +<td>18.19</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">All</td> +<td data-quarto-table-cell-role="th">rmse</td> +<td>45.19</td> +<td>54.95</td> +<td>44.59</td> +<td>42.71</td> +</tr> +</tbody> +</table> + +</div> +</div> +</div> +</section> +<section id="mase" class="level3"> +<h3 class="anchored" data-anchor-id="mase">MASE</h3> +<p>The following table shows the performance measured using MASE across levels for each reconciliation method.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb24"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb24-1"><a href="#cb24-1" aria-hidden="true" tabindex="-1"></a>evaluation.query(<span class="st">'metric == "mase"'</span>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<div> + + +<table class="dataframe table table-sm table-striped small" data-quarto-postprocess="true" data-border="1"> +<thead> +<tr class="header"> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th">Base</th> +<th data-quarto-table-cell-role="th">BottomUp</th> +<th data-quarto-table-cell-role="th">MinTrace(mint_shrink)</th> +<th data-quarto-table-cell-role="th">MinTrace(ols)</th> +</tr> +<tr class="odd"> +<th data-quarto-table-cell-role="th">level</th> +<th data-quarto-table-cell-role="th">metric</th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td data-quarto-table-cell-role="th">Total</td> +<td data-quarto-table-cell-role="th">mase</td> +<td>1.59</td> +<td>3.16</td> +<td>2.05</td> +<td>1.67</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">Purpose</td> +<td data-quarto-table-cell-role="th">mase</td> +<td>1.32</td> +<td>2.28</td> +<td>1.48</td> +<td>1.25</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">State</td> +<td data-quarto-table-cell-role="th">mase</td> +<td>1.39</td> +<td>1.90</td> +<td>1.39</td> +<td>1.25</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">Regions</td> +<td data-quarto-table-cell-role="th">mase</td> +<td>1.12</td> +<td>1.19</td> +<td>1.01</td> +<td>0.99</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">Bottom</td> +<td data-quarto-table-cell-role="th">mase</td> +<td>0.98</td> +<td>0.98</td> +<td>0.94</td> +<td>1.01</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">All</td> +<td data-quarto-table-cell-role="th">mase</td> +<td>1.03</td> +<td>1.08</td> +<td>0.98</td> +<td>1.02</td> +</tr> +</tbody> +</table> + +</div> +</div> +</div> +</section> +<section id="comparison-fable" class="level3"> +<h3 class="anchored" data-anchor-id="comparison-fable">Comparison fable</h3> +<p>Observe that we can recover the results reported by the <a href="https://otexts.com/fpp3/tourism.html">Forecasting: Principles and Practice</a>. The original results were calculated using the R package <a href="https://github.com/tidyverts/fable">fable</a>.</p> +<div class="quarto-figure quarto-figure-center"> +<figure class="figure"> +<p><img src="./imgs/AustralianDomesticTourism-results-fable.png" class="img-fluid figure-img"></p> +<figcaption class="figure-caption">Fableās reconciliation results</figcaption> +</figure> +</div> +</section> +<section id="references" class="level3"> +<h3 class="anchored" data-anchor-id="references">References</h3> +<ul> +<li><a href="https://otexts.com/fpp3/hierarchical.html">Hyndman, R.J., & Athanasopoulos, G. (2021). āForecasting: principles and practice, 3rd edition: Chapter 11: Forecasting hierarchical and grouped series.ā. OTexts: Melbourne, Australia. OTexts.com/fpp3 Accessed on July 2022.</a></li> +<li><a href="https://cran.r-project.org/web/packages/hts/index.html">Rob Hyndman, Alan Lee, Earo Wang, Shanika Wickramasuriya, and Maintainer Earo Wang (2021). āhts: Hierarchical and Grouped Time Seriesā. URL https://CRAN.R-project.org/package=hts. R package version 0.3.1.</a></li> +<li><a href="https://CRAN.R-project.org/package=fable">Mitchell OāHara-Wild, Rob Hyndman, Earo Wang, Gabriel Caceres, Tim-Gunnar Hensel, and Timothy Hyndman (2021). āfable: Forecasting Models for Tidy Time Seriesā. URL https://CRAN.R-project.org/package=fable. R package version 6.0.2.</a></li> +</ul> + + +</section> +</section> + +<p>If you find the code useful, please ā us on <a href="https://github.com/nixtla/hierarchicalforecast">Github</a></p></main> <!-- /main --> +<script id="quarto-html-after-body" type="application/javascript"> +window.document.addEventListener("DOMContentLoaded", function (event) { + const toggleBodyColorMode = (bsSheetEl) => { + const mode = bsSheetEl.getAttribute("data-mode"); + const bodyEl = window.document.querySelector("body"); + if (mode === "dark") { + bodyEl.classList.add("quarto-dark"); + bodyEl.classList.remove("quarto-light"); + } else { + bodyEl.classList.add("quarto-light"); + bodyEl.classList.remove("quarto-dark"); + } + } + const toggleBodyColorPrimary = () => { + const bsSheetEl = window.document.querySelector("link#quarto-bootstrap"); + if (bsSheetEl) { + toggleBodyColorMode(bsSheetEl); + } + } + toggleBodyColorPrimary(); + const icon = "ī§"; + const anchorJS = new window.AnchorJS(); + anchorJS.options = { + placement: 'right', + icon: icon + }; + anchorJS.add('.anchored'); + const isCodeAnnotation = (el) => { + for (const clz of el.classList) { + if (clz.startsWith('code-annotation-')) { + return true; + } + } + return false; + } + const clipboard = new window.ClipboardJS('.code-copy-button', { + text: function(trigger) { + const codeEl = trigger.previousElementSibling.cloneNode(true); + for (const childEl of codeEl.children) { + if (isCodeAnnotation(childEl)) { + childEl.remove(); + } + } + return codeEl.innerText; + } + }); + clipboard.on('success', function(e) { + // button target + const button = e.trigger; + // don't keep focus + button.blur(); + // flash "checked" + button.classList.add('code-copy-button-checked'); + var currentTitle = button.getAttribute("title"); + button.setAttribute("title", "Copied!"); + let tooltip; + if (window.bootstrap) { + button.setAttribute("data-bs-toggle", "tooltip"); + button.setAttribute("data-bs-placement", "left"); + button.setAttribute("data-bs-title", "Copied!"); + tooltip = new bootstrap.Tooltip(button, + { trigger: "manual", + customClass: "code-copy-button-tooltip", + offset: [0, -8]}); + tooltip.show(); + } + setTimeout(function() { + if (tooltip) { + tooltip.hide(); + button.removeAttribute("data-bs-title"); + button.removeAttribute("data-bs-toggle"); + button.removeAttribute("data-bs-placement"); + } + button.setAttribute("title", currentTitle); + button.classList.remove('code-copy-button-checked'); + }, 1000); + // clear code selection + e.clearSelection(); + }); + function tippyHover(el, contentFn) { + const config = { + allowHTML: true, + content: contentFn, + maxWidth: 500, + delay: 100, + arrow: false, + appendTo: function(el) { + return el.parentElement; + }, + interactive: true, + interactiveBorder: 10, + theme: 'quarto', + placement: 'bottom-start' + }; + window.tippy(el, config); + } + const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]'); + for (var i=0; i<noterefs.length; i++) { + const ref = noterefs[i]; + tippyHover(ref, function() { + // use id or data attribute instead here + let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href'); + try { href = new URL(href).hash; } catch {} + const id = href.replace(/^#\/?/, ""); + const note = window.document.getElementById(id); + return note.innerHTML; + }); + } + let selectedAnnoteEl; + const selectorForAnnotation = ( cell, annotation) => { + let cellAttr = 'data-code-cell="' + cell + '"'; + let lineAttr = 'data-code-annotation="' + annotation + '"'; + const selector = 'span[' + cellAttr + '][' + lineAttr + ']'; + return selector; + } + const selectCodeLines = (annoteEl) => { + const doc = window.document; + const targetCell = annoteEl.getAttribute("data-target-cell"); + const targetAnnotation = annoteEl.getAttribute("data-target-annotation"); + const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation)); + const lines = annoteSpan.getAttribute("data-code-lines").split(","); + const lineIds = lines.map((line) => { + return targetCell + "-" + line; + }) + let top = null; + let height = null; + let parent = null; + if (lineIds.length > 0) { + //compute the position of the single el (top and bottom and make a div) + const el = window.document.getElementById(lineIds[0]); + top = el.offsetTop; + height = el.offsetHeight; + parent = el.parentElement.parentElement; + if (lineIds.length > 1) { + const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]); + const bottom = lastEl.offsetTop + lastEl.offsetHeight; + height = bottom - top; + } + if (top !== null && height !== null && parent !== null) { + // cook up a div (if necessary) and position it + let div = window.document.getElementById("code-annotation-line-highlight"); + if (div === null) { + div = window.document.createElement("div"); + div.setAttribute("id", "code-annotation-line-highlight"); + div.style.position = 'absolute'; + parent.appendChild(div); + } + div.style.top = top - 2 + "px"; + div.style.height = height + 4 + "px"; + let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter"); + if (gutterDiv === null) { + gutterDiv = window.document.createElement("div"); + gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter"); + gutterDiv.style.position = 'absolute'; + const codeCell = window.document.getElementById(targetCell); + const gutter = codeCell.querySelector('.code-annotation-gutter'); + gutter.appendChild(gutterDiv); + } + gutterDiv.style.top = top - 2 + "px"; + gutterDiv.style.height = height + 4 + "px"; + } + selectedAnnoteEl = annoteEl; + } + }; + const unselectCodeLines = () => { + const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"]; + elementsIds.forEach((elId) => { + const div = window.document.getElementById(elId); + if (div) { + div.remove(); + } + }); + selectedAnnoteEl = undefined; + }; + // Attach click handler to the DT + const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); + for (const annoteDlNode of annoteDls) { + annoteDlNode.addEventListener('click', (event) => { + const clickedEl = event.target; + if (clickedEl !== selectedAnnoteEl) { + unselectCodeLines(); + const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active'); + if (activeEl) { + activeEl.classList.remove('code-annotation-active'); + } + selectCodeLines(clickedEl); + clickedEl.classList.add('code-annotation-active'); + } else { + // Unselect the line + unselectCodeLines(); + clickedEl.classList.remove('code-annotation-active'); + } + }); + } + const findCites = (el) => { + const parentEl = el.parentElement; + if (parentEl) { + const cites = parentEl.dataset.cites; + if (cites) { + return { + el, + cites: cites.split(' ') + }; + } else { + return findCites(el.parentElement) + } + } else { + return undefined; + } + }; + var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]'); + for (var i=0; i<bibliorefs.length; i++) { + const ref = bibliorefs[i]; + const citeInfo = findCites(ref); + if (citeInfo) { + tippyHover(citeInfo.el, function() { + var popup = window.document.createElement('div'); + citeInfo.cites.forEach(function(cite) { + var citeDiv = window.document.createElement('div'); + citeDiv.classList.add('hanging-indent'); + citeDiv.classList.add('csl-entry'); + var biblioDiv = window.document.getElementById('ref-' + cite); + if (biblioDiv) { + citeDiv.innerHTML = biblioDiv.innerHTML; + } + popup.appendChild(citeDiv); + }); + return popup.innerHTML; + }); + } + } +}); +</script> +</div> <!-- /content --> + + + +</body></html> \ No newline at end of file diff --git a/examples/australianprisonpopulation.html b/examples/australianprisonpopulation.html new file mode 100644 index 00000000..d52f89f9 --- /dev/null +++ b/examples/australianprisonpopulation.html @@ -0,0 +1,1193 @@ +<!DOCTYPE html> +<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head> + +<meta charset="utf-8"> +<meta name="generator" content="quarto-1.3.450"> + +<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes"> + +<meta name="description" content="Geographical Hierarchical Forecasting on Australian Prison Population Data"> + +<title>hierarchicalforecast - Geographical Aggregation (Prison Population)</title> +<style> +code{white-space: pre-wrap;} +span.smallcaps{font-variant: small-caps;} +div.columns{display: flex; gap: min(4vw, 1.5em);} +div.column{flex: auto; overflow-x: auto;} +div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;} +ul.task-list{list-style: none;} +ul.task-list li input[type="checkbox"] { + width: 0.8em; + margin: 0 0.8em 0.2em -1em; /* quarto-specific, see https://github.com/quarto-dev/quarto-cli/issues/4556 */ + vertical-align: middle; +} +/* CSS for syntax highlighting */ +pre > code.sourceCode { white-space: pre; position: relative; } +pre > code.sourceCode > span { display: inline-block; line-height: 1.25; } +pre > code.sourceCode > span:empty { height: 1.2em; } +.sourceCode { overflow: visible; } +code.sourceCode > span { color: inherit; text-decoration: inherit; } +div.sourceCode { margin: 1em 0; } +pre.sourceCode { margin: 0; } +@media screen { +div.sourceCode { overflow: auto; } +} +@media print { +pre > code.sourceCode { white-space: pre-wrap; } +pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; } +} +pre.numberSource code + { counter-reset: source-line 0; } +pre.numberSource code > span + { position: relative; left: -4em; counter-increment: source-line; } +pre.numberSource code > span > a:first-child::before + { content: counter(source-line); + position: relative; left: -1em; text-align: right; vertical-align: baseline; + border: none; display: inline-block; + -webkit-touch-callout: none; -webkit-user-select: none; + -khtml-user-select: none; -moz-user-select: none; + -ms-user-select: none; user-select: none; + padding: 0 4px; width: 4em; + } +pre.numberSource { margin-left: 3em; padding-left: 4px; } +div.sourceCode + { } +@media screen { +pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; } +} +</style> + + +<script src="../site_libs/quarto-nav/quarto-nav.js"></script> +<script src="../site_libs/quarto-nav/headroom.min.js"></script> +<script src="../site_libs/clipboard/clipboard.min.js"></script> +<script src="../site_libs/quarto-search/autocomplete.umd.js"></script> +<script src="../site_libs/quarto-search/fuse.min.js"></script> +<script src="../site_libs/quarto-search/quarto-search.js"></script> +<meta name="quarto:offset" content="../"> +<link href="../favicon_png.png" rel="icon" type="image/png"> +<script src="../site_libs/quarto-html/quarto.js"></script> +<script src="../site_libs/quarto-html/popper.min.js"></script> +<script src="../site_libs/quarto-html/tippy.umd.min.js"></script> +<script src="../site_libs/quarto-html/anchor.min.js"></script> +<link href="../site_libs/quarto-html/tippy.css" rel="stylesheet"> +<link href="../site_libs/quarto-html/quarto-syntax-highlighting.css" rel="stylesheet" id="quarto-text-highlighting-styles"> +<script src="../site_libs/bootstrap/bootstrap.min.js"></script> +<link href="../site_libs/bootstrap/bootstrap-icons.css" rel="stylesheet"> +<link href="../site_libs/bootstrap/bootstrap.min.css" rel="stylesheet" id="quarto-bootstrap" data-mode="light"> +<script id="quarto-search-options" type="application/json">{ + "location": "navbar", + "copy-button": false, + "collapse-after": 3, + "panel-placement": "end", + "type": "overlay", + "limit": 20, + "language": { + "search-no-results-text": "No results", + "search-matching-documents-text": "matching documents", + "search-copy-link-title": "Copy link to search", + "search-hide-matches-text": "Hide additional matches", + "search-more-match-text": "more match in this document", + "search-more-matches-text": "more matches in this document", + "search-clear-button-title": "Clear", + "search-detached-cancel-button-title": "Cancel", + "search-submit-button-title": "Submit", + "search-label": "Search" + } +}</script> +<script async="" src="https://www.googletagmanager.com/gtag/js?id=G-NXJNCVR18L"></script> + +<script type="text/javascript"> + +window.dataLayer = window.dataLayer || []; +function gtag(){dataLayer.push(arguments);} +gtag('js', new Date()); +gtag('config', 'G-NXJNCVR18L', { 'anonymize_ip': true}); +</script> +<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js" integrity="sha512-c3Nl8+7g4LMSTdrm621y7kf9v3SDPnhxLNhcjFJbKECVnmZHTdo+IRO05sNLTH/D3vA6u1X32ehoLC7WFVdheg==" crossorigin="anonymous"></script> +<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js" integrity="sha512-bLT0Qm9VnAYZDflyKcBaQ2gg0hSYNQrJ8RilYldYQ1FxQYoCLtUjuuRuZo+fjqhx/qtq/1itJ0C2ejDxltZVFg==" crossorigin="anonymous"></script> +<script type="application/javascript">define('jquery', [],function() {return window.jQuery;})</script> + + +<link rel="stylesheet" href="../styles.css"> +<meta property="og:title" content="hierarchicalforecast - Geographical Aggregation (Prison Population)"> +<meta property="og:description" content="Geographical Hierarchical Forecasting on Australian Prison Population Data"> +<meta property="og:image" content="https://colab.research.google.com/assets/colab-badge.svg"> +<meta property="og:site-name" content="hierarchicalforecast"> +<meta name="twitter:title" content="hierarchicalforecast - Geographical Aggregation (Prison Population)"> +<meta name="twitter:description" content="Geographical Hierarchical Forecasting on Australian Prison Population Data"> +<meta name="twitter:image" content="https://colab.research.google.com/assets/colab-badge.svg"> +<meta name="twitter:card" content="summary_large_image"> +</head> + +<body class="nav-sidebar floating nav-fixed"> + +<div id="quarto-search-results"></div> + <header id="quarto-header" class="headroom fixed-top"> + <nav class="navbar navbar-expand-lg navbar-dark "> + <div class="navbar-container container-fluid"> + <div class="navbar-brand-container"> + <a class="navbar-brand" href="../index.html"> + <span class="navbar-title">hierarchicalforecast</span> + </a> + </div> + <div id="quarto-search" class="" title="Search"></div> + <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + <span class="navbar-toggler-icon"></span> +</button> + <div class="collapse navbar-collapse" id="navbarCollapse"> + <ul class="navbar-nav navbar-nav-scroll me-auto"> + <li class="nav-item"> + <a class="nav-link active" href="../examples/tourismsmall.html" rel="" target="" aria-current="page"> + <span class="menu-text">Get Started</span></a> + </li> + <li class="nav-item dropdown "> + <a class="nav-link dropdown-toggle" href="#" id="nav-menu-nixtlaverse" role="button" data-bs-toggle="dropdown" aria-expanded="false" rel="" target=""> + <span class="menu-text">NixtlaVerse</span> + </a> + <ul class="dropdown-menu" aria-labelledby="nav-menu-nixtlaverse"> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/mlforecast" rel="" target=""> + <span class="dropdown-text">MLForecast š¤</span></a> + </li> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/neuralforecast" rel="" target=""> + <span class="dropdown-text">NeuralForecast š§ </span></a> + </li> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/statsforecast" rel="" target=""> + <span class="dropdown-text">StatsForecast ā”ļø</span></a> + </li> + </ul> + </li> + <li class="nav-item dropdown "> + <a class="nav-link dropdown-toggle" href="#" id="nav-menu-help" role="button" data-bs-toggle="dropdown" aria-expanded="false" rel="" target=""> + <span class="menu-text">Help</span> + </a> + <ul class="dropdown-menu" aria-labelledby="nav-menu-help"> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/hierarchicalforecast/issues/new/choose" rel="" target=""><i class="bi bi-bug" role="img"> +</i> + <span class="dropdown-text">Report an Issue</span></a> + </li> + <li> + <a class="dropdown-item" href="https://join.slack.com/t/nixtlacommunity/shared_invite/zt-1kd5m5db7-7OOfy0xVNf1PcvCiAPWvPw" rel="" target=""><i class="bi bi-chat-right-text" role="img"> +</i> + <span class="dropdown-text">Join our Slack</span></a> + </li> + </ul> + </li> +</ul> + <ul class="navbar-nav navbar-nav-scroll ms-auto"> + <li class="nav-item compact"> + <a class="nav-link" href="https://github.com/nixtla/hierarchicalforecast" rel="" target=""><i class="bi bi-github" role="img"> +</i> + <span class="menu-text"></span></a> + </li> + <li class="nav-item compact"> + <a class="nav-link" href="https://twitter.com/nixtlainc" rel="" target=""><i class="bi bi-twitter" role="img" aria-label="Nixtla Twitter"> +</i> + <span class="menu-text"></span></a> + </li> +</ul> + <div class="quarto-navbar-tools"> +</div> + </div> <!-- /navcollapse --> + </div> <!-- /container-fluid --> + </nav> + <nav class="quarto-secondary-nav"> + <div class="container-fluid d-flex"> + <button type="button" class="quarto-btn-toggle btn" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + <i class="bi bi-layout-text-sidebar-reverse"></i> + </button> + <nav class="quarto-page-breadcrumbs" aria-label="breadcrumb"><ol class="breadcrumb"><li class="breadcrumb-item">Tutorials</li><li class="breadcrumb-item"><a href="../examples/australiandomestictourism.html">Point Reconciliation</a></li><li class="breadcrumb-item"><a href="../examples/australianprisonpopulation.html">Geographical Aggregation (Prison Population)</a></li></ol></nav> + <a class="flex-grow-1" role="button" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + </a> + </div> + </nav> +</header> +<!-- content --> +<div id="quarto-content" class="quarto-container page-columns page-rows-contents page-layout-article page-navbar"> +<!-- sidebar --> + <nav id="quarto-sidebar" class="sidebar collapse collapse-horizontal sidebar-navigation floating overflow-auto"> + <div class="sidebar-menu-container"> + <ul class="list-unstyled mt-1"> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../index.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Hierarchical Forecast š</span></a> + </div> +</li> + <li class="px-0"><hr class="sidebar-divider hi "></li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-1" aria-expanded="false"> + <span class="menu-text">Getting Started</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-1" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-1" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/installation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Install</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/tourismsmall.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Reconciliation Quick Start</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/introduction.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Introduction</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-2" aria-expanded="true"> + <span class="menu-text">Tutorials</span></a> + <a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-2" aria-expanded="true" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-2" class="collapse list-unstyled sidebar-section depth1 show"> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-3" aria-expanded="true"> + <span class="menu-text">Point Reconciliation</span></a> + <a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-3" aria-expanded="true" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-3" class="collapse list-unstyled sidebar-section depth2 show"> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Geographical Aggregation (Tourism)</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australianprisonpopulation.html" class="sidebar-item-text sidebar-link active"> + <span class="menu-text">Geographical Aggregation (Prison Population)</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/nonnegativereconciliation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Non-Negative MinTrace</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-4" aria-expanded="false"> + <span class="menu-text">Probabilistic Reconciliation</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-4" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-4" class="collapse list-unstyled sidebar-section depth2 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Normality</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism-bootstraped-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Bootstrap</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism-permbu-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">PERMBU</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/tourismlarge-evaluation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Probabilistic Forecast Evaluation</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-5" aria-expanded="false"> + <span class="menu-text">ML Forecast Reconciliation</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-5" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-5" class="collapse list-unstyled sidebar-section depth2 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/hierarchicalforecast-gluonts.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">GluonTS</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/mlframeworksexample.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Neural/MLForecast</span></a> + </div> +</li> + </ul> + </li> + </ul> + </li> + <li class="sidebar-item"> + <span class="menu-text">Methods</span> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-6" aria-expanded="false"> + <span class="menu-text">API Reference</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-6" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-6" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../core.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Core </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../methods.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Reconciliation Methods </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../probabilistic_methods.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Probabilistic Methods </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../evaluation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Hierarchical Evaluation</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../utils.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Aggregation/Visualization Utils</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-7" aria-expanded="false"> + <span class="menu-text">Community</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-7" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-7" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item"> + <span class="menu-text">Contributing</span> + </li> + </ul> + </li> + </ul> + </div> +</nav> +<div id="quarto-sidebar-glass" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass"></div> +<!-- margin-sidebar --> + <div id="quarto-margin-sidebar" class="sidebar margin-sidebar"> + <nav id="TOC" role="doc-toc" class="toc-active"> + <h2 id="toc-title">On this page</h2> + + <ul> + <li><a href="#load-and-process-data" id="toc-load-and-process-data" class="nav-link active" data-scroll-target="#load-and-process-data">1. Load and Process Data</a> + <ul class="collapse"> + <li><a href="#split-traintest-sets" id="toc-split-traintest-sets" class="nav-link" data-scroll-target="#split-traintest-sets">Split Train/Test sets</a></li> + </ul></li> + <li><a href="#computing-base-forecasts" id="toc-computing-base-forecasts" class="nav-link" data-scroll-target="#computing-base-forecasts">2. Computing base forecasts</a></li> + <li><a href="#reconcile-forecasts" id="toc-reconcile-forecasts" class="nav-link" data-scroll-target="#reconcile-forecasts">3. Reconcile forecasts</a></li> + <li><a href="#evaluation" id="toc-evaluation" class="nav-link" data-scroll-target="#evaluation">4. Evaluation</a> + <ul class="collapse"> + <li><a href="#fable-comparison" id="toc-fable-comparison" class="nav-link" data-scroll-target="#fable-comparison">Fable Comparison</a></li> + <li><a href="#references" id="toc-references" class="nav-link" data-scroll-target="#references">References</a></li> + </ul></li> + </ul> +<div class="toc-actions"><div><i class="bi bi-github"></i></div><div class="action-links"><p><a href="https://github.com/Nixtla/hierarchicalforecast/issues/new" class="toc-action">Report an issue</a></p></div></div></nav> + </div> +<!-- main --> +<main class="content" id="quarto-document-content"> + +<header id="title-block-header" class="quarto-title-block default"> +<div class="quarto-title"> +<h1 class="title">Geographical Aggregation (Prison Population)</h1> +</div> + +<div> + <div class="description"> + Geographical Hierarchical Forecasting on Australian Prison Population Data + </div> +</div> + + +<div class="quarto-title-meta"> + + + + + </div> + + +</header> + +<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! --> +<p>In many applications, a set of time series is hierarchically organized. Examples include the presence of geographic levels, products, or categories that define different types of aggregations. In such scenarios, forecasters are often required to provide predictions for all disaggregate and aggregate series. A natural desire is for those predictions to be <strong>ācoherentā</strong>, that is, for the bottom series to add up precisely to the forecasts of the aggregated series.</p> +<p>In this notebook we present an example on how to use <code>HierarchicalForecast</code> to produce coherent forecasts between geographical levels. We will use the Australian Prison Population dataset.</p> +<p>We will first load the dataset and produce base forecasts using an <code>ETS</code> model from <code>StatsForecast</code>, and then reconciliate the forecasts with several reconciliation algorithms from <code>HierarchicalForecast</code>. Finally, we show the performance is comparable with the results reported by the <a href="https://otexts.com/fpp3/tourism.html">Forecasting: Principles and Practice</a> which uses the R package <a href="https://github.com/tidyverts/fable">fable</a>.</p> +<p>You can run these experiments using CPU or GPU with Google Colab.</p> +<p><a href="https://colab.research.google.com/github/Nixtla/hierarchicalforecast/blob/main/nbs/examples/AustralianPrisonPopulation.ipynb" target="_parent"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"></a></p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb1"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="op">!</span>pip install hierarchicalforecast</span> +<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="op">!</span>pip install <span class="op">-</span>U statsforecast numba</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<section id="load-and-process-data" class="level2"> +<h2 class="anchored" data-anchor-id="load-and-process-data">1. Load and Process Data</h2> +<p>The dataset only contains the time series at the lowest level, so we need to create the time series for all hierarchies.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb2"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> numpy <span class="im">as</span> np</span> +<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> pandas <span class="im">as</span> pd</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb3"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a>Y_df <span class="op">=</span> pd.read_csv(<span class="st">'https://OTexts.com/fpp3/extrafiles/prison_population.csv'</span>)</span> +<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>Y_df <span class="op">=</span> Y_df.rename({<span class="st">'Count'</span>: <span class="st">'y'</span>, <span class="st">'Date'</span>: <span class="st">'ds'</span>}, axis<span class="op">=</span><span class="dv">1</span>)</span> +<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>Y_df.insert(<span class="dv">0</span>, <span class="st">'Country'</span>, <span class="st">'Australia'</span>)</span> +<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>Y_df <span class="op">=</span> Y_df[[<span class="st">'Country'</span>, <span class="st">'State'</span>, <span class="st">'Gender'</span>, <span class="st">'Legal'</span>, <span class="st">'Indigenous'</span>, <span class="st">'ds'</span>, <span class="st">'y'</span>]]</span> +<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>Y_df[<span class="st">'ds'</span>] <span class="op">=</span> pd.to_datetime(Y_df[<span class="st">'ds'</span>])</span> +<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>Y_df.head()</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<div> + + +<table class="dataframe table table-sm table-striped small" data-quarto-postprocess="true" data-border="1"> +<thead> +<tr class="header"> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th">Country</th> +<th data-quarto-table-cell-role="th">State</th> +<th data-quarto-table-cell-role="th">Gender</th> +<th data-quarto-table-cell-role="th">Legal</th> +<th data-quarto-table-cell-role="th">Indigenous</th> +<th data-quarto-table-cell-role="th">ds</th> +<th data-quarto-table-cell-role="th">y</th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td data-quarto-table-cell-role="th">0</td> +<td>Australia</td> +<td>ACT</td> +<td>Female</td> +<td>Remanded</td> +<td>ATSI</td> +<td>2005-03-01</td> +<td>0</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">1</td> +<td>Australia</td> +<td>ACT</td> +<td>Female</td> +<td>Remanded</td> +<td>Non-ATSI</td> +<td>2005-03-01</td> +<td>2</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">2</td> +<td>Australia</td> +<td>ACT</td> +<td>Female</td> +<td>Sentenced</td> +<td>ATSI</td> +<td>2005-03-01</td> +<td>0</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">3</td> +<td>Australia</td> +<td>ACT</td> +<td>Female</td> +<td>Sentenced</td> +<td>Non-ATSI</td> +<td>2005-03-01</td> +<td>5</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">4</td> +<td>Australia</td> +<td>ACT</td> +<td>Male</td> +<td>Remanded</td> +<td>ATSI</td> +<td>2005-03-01</td> +<td>7</td> +</tr> +</tbody> +</table> + +</div> +</div> +</div> +<p>The dataset can be grouped in the following grouped structure.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb4"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a>hiers <span class="op">=</span> [</span> +<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a> [<span class="st">'Country'</span>],</span> +<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a> [<span class="st">'Country'</span>, <span class="st">'State'</span>], </span> +<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a> [<span class="st">'Country'</span>, <span class="st">'Gender'</span>], </span> +<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a> [<span class="st">'Country'</span>, <span class="st">'Legal'</span>], </span> +<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a> [<span class="st">'Country'</span>, <span class="st">'State'</span>, <span class="st">'Gender'</span>, <span class="st">'Legal'</span>]</span> +<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>]</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<p>Using the <a href="https://Nixtla.github.io/hierarchicalforecast/utils.html#aggregate"><code>aggregate</code></a> function from <code>HierarchicalForecast</code> we can get the full set of time series.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb5"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> hierarchicalforecast.utils <span class="im">import</span> aggregate</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb6"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a>Y_df, S_df, tags <span class="op">=</span> aggregate(Y_df, hiers)</span> +<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>Y_df[<span class="st">'y'</span>] <span class="op">=</span> Y_df[<span class="st">'y'</span>]<span class="op">/</span><span class="fl">1e3</span></span> +<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>Y_df <span class="op">=</span> Y_df.reset_index()</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb7"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a>Y_df.head()</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<div> + + +<table class="dataframe table table-sm table-striped small" data-quarto-postprocess="true" data-border="1"> +<thead> +<tr class="header"> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th">unique_id</th> +<th data-quarto-table-cell-role="th">ds</th> +<th data-quarto-table-cell-role="th">y</th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td data-quarto-table-cell-role="th">0</td> +<td>Australia</td> +<td>2005-03-01</td> +<td>24.296</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">1</td> +<td>Australia</td> +<td>2005-06-01</td> +<td>24.643</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">2</td> +<td>Australia</td> +<td>2005-09-01</td> +<td>24.511</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">3</td> +<td>Australia</td> +<td>2005-12-01</td> +<td>24.393</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">4</td> +<td>Australia</td> +<td>2006-03-01</td> +<td>24.524</td> +</tr> +</tbody> +</table> + +</div> +</div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb8"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a>S_df.iloc[:<span class="dv">5</span>, :<span class="dv">5</span>]</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<div> + + +<table class="dataframe table table-sm table-striped small" data-quarto-postprocess="true" data-border="1"> +<thead> +<tr class="header"> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th">Australia/ACT/Female/Remanded</th> +<th data-quarto-table-cell-role="th">Australia/ACT/Female/Sentenced</th> +<th data-quarto-table-cell-role="th">Australia/ACT/Male/Remanded</th> +<th data-quarto-table-cell-role="th">Australia/ACT/Male/Sentenced</th> +<th data-quarto-table-cell-role="th">Australia/NSW/Female/Remanded</th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td data-quarto-table-cell-role="th">Australia</td> +<td>1.0</td> +<td>1.0</td> +<td>1.0</td> +<td>1.0</td> +<td>1.0</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">Australia/ACT</td> +<td>1.0</td> +<td>1.0</td> +<td>1.0</td> +<td>1.0</td> +<td>0.0</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">Australia/NSW</td> +<td>0.0</td> +<td>0.0</td> +<td>0.0</td> +<td>0.0</td> +<td>1.0</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">Australia/NT</td> +<td>0.0</td> +<td>0.0</td> +<td>0.0</td> +<td>0.0</td> +<td>0.0</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">Australia/QLD</td> +<td>0.0</td> +<td>0.0</td> +<td>0.0</td> +<td>0.0</td> +<td>0.0</td> +</tr> +</tbody> +</table> + +</div> +</div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb9"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a>tags</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<pre><code>{'Country': array(['Australia'], dtype=object), + 'Country/State': array(['Australia/ACT', 'Australia/NSW', 'Australia/NT', 'Australia/QLD', + 'Australia/SA', 'Australia/TAS', 'Australia/VIC', 'Australia/WA'], + dtype=object), + 'Country/Gender': array(['Australia/Female', 'Australia/Male'], dtype=object), + 'Country/Legal': array(['Australia/Remanded', 'Australia/Sentenced'], dtype=object), + 'Country/State/Gender/Legal': ['Australia/ACT/Female/Remanded', + 'Australia/ACT/Female/Sentenced', + 'Australia/ACT/Male/Remanded', + 'Australia/ACT/Male/Sentenced', + 'Australia/NSW/Female/Remanded', + 'Australia/NSW/Female/Sentenced', + 'Australia/NSW/Male/Remanded', + 'Australia/NSW/Male/Sentenced', + 'Australia/NT/Female/Remanded', + 'Australia/NT/Female/Sentenced', + 'Australia/NT/Male/Remanded', + 'Australia/NT/Male/Sentenced', + 'Australia/QLD/Female/Remanded', + 'Australia/QLD/Female/Sentenced', + 'Australia/QLD/Male/Remanded', + 'Australia/QLD/Male/Sentenced', + 'Australia/SA/Female/Remanded', + 'Australia/SA/Female/Sentenced', + 'Australia/SA/Male/Remanded', + 'Australia/SA/Male/Sentenced', + 'Australia/TAS/Female/Remanded', + 'Australia/TAS/Female/Sentenced', + 'Australia/TAS/Male/Remanded', + 'Australia/TAS/Male/Sentenced', + 'Australia/VIC/Female/Remanded', + 'Australia/VIC/Female/Sentenced', + 'Australia/VIC/Male/Remanded', + 'Australia/VIC/Male/Sentenced', + 'Australia/WA/Female/Remanded', + 'Australia/WA/Female/Sentenced', + 'Australia/WA/Male/Remanded', + 'Australia/WA/Male/Sentenced']}</code></pre> +</div> +</div> +<section id="split-traintest-sets" class="level3"> +<h3 class="anchored" data-anchor-id="split-traintest-sets">Split Train/Test sets</h3> +<p>We use the final two years (8 quarters) as test set.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb11"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a>Y_test_df <span class="op">=</span> Y_df.groupby(<span class="st">'unique_id'</span>).tail(<span class="dv">8</span>)</span> +<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a>Y_train_df <span class="op">=</span> Y_df.drop(Y_test_df.index)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb12"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a>Y_test_df <span class="op">=</span> Y_test_df.set_index(<span class="st">'unique_id'</span>)</span> +<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a>Y_train_df <span class="op">=</span> Y_train_df.set_index(<span class="st">'unique_id'</span>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +</section> +</section> +<section id="computing-base-forecasts" class="level2"> +<h2 class="anchored" data-anchor-id="computing-base-forecasts">2. Computing base forecasts</h2> +<p>The following cell computes the <strong>base forecasts</strong> for each time series in <code>Y_df</code> using the <code>ETS</code> model. Observe that <code>Y_hat_df</code> contains the forecasts but they are not coherent.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb13"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> statsforecast.models <span class="im">import</span> ETS</span> +<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> statsforecast.core <span class="im">import</span> StatsForecast</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb14"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a>fcst <span class="op">=</span> StatsForecast(df<span class="op">=</span>Y_train_df,</span> +<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a> models<span class="op">=</span>[ETS(season_length<span class="op">=</span><span class="dv">4</span>, model<span class="op">=</span><span class="st">'ZMZ'</span>)], </span> +<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a> freq<span class="op">=</span><span class="st">'QS'</span>, n_jobs<span class="op">=-</span><span class="dv">1</span>)</span> +<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a>Y_hat_df <span class="op">=</span> fcst.forecast(h<span class="op">=</span><span class="dv">8</span>, fitted<span class="op">=</span><span class="va">True</span>)</span> +<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a>Y_fitted_df <span class="op">=</span> fcst.forecast_fitted_values()</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +</section> +<section id="reconcile-forecasts" class="level2"> +<h2 class="anchored" data-anchor-id="reconcile-forecasts">3. Reconcile forecasts</h2> +<p>The following cell makes the previous forecasts coherent using the <a href="https://Nixtla.github.io/hierarchicalforecast/core.html#hierarchicalreconciliation"><code>HierarchicalReconciliation</code></a> class. Since the hierarchy structure is not strict, we canāt use methods such as <a href="https://Nixtla.github.io/hierarchicalforecast/methods.html#topdown"><code>TopDown</code></a> or <a href="https://Nixtla.github.io/hierarchicalforecast/methods.html#middleout"><code>MiddleOut</code></a>. In this example we use <a href="https://Nixtla.github.io/hierarchicalforecast/methods.html#bottomup"><code>BottomUp</code></a> and <a href="https://Nixtla.github.io/hierarchicalforecast/methods.html#mintrace"><code>MinTrace</code></a>.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb15"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> hierarchicalforecast.methods <span class="im">import</span> BottomUp, MinTrace</span> +<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> hierarchicalforecast.core <span class="im">import</span> HierarchicalReconciliation</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb16"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a>reconcilers <span class="op">=</span> [</span> +<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a> BottomUp(),</span> +<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a> MinTrace(method<span class="op">=</span><span class="st">'mint_shrink'</span>)</span> +<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a>]</span> +<span id="cb16-5"><a href="#cb16-5" aria-hidden="true" tabindex="-1"></a>hrec <span class="op">=</span> HierarchicalReconciliation(reconcilers<span class="op">=</span>reconcilers)</span> +<span id="cb16-6"><a href="#cb16-6" aria-hidden="true" tabindex="-1"></a>Y_rec_df <span class="op">=</span> hrec.reconcile(Y_hat_df<span class="op">=</span>Y_hat_df, Y_df<span class="op">=</span>Y_fitted_df, S<span class="op">=</span>S_df, tags<span class="op">=</span>tags)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<p>The dataframe <code>Y_rec_df</code> contains the reconciled forecasts.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb17"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a>Y_rec_df.head()</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<div> + + +<table class="dataframe table table-sm table-striped small" data-quarto-postprocess="true" data-border="1"> +<thead> +<tr class="header"> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th">ds</th> +<th data-quarto-table-cell-role="th">ETS</th> +<th data-quarto-table-cell-role="th">ETS/BottomUp</th> +<th data-quarto-table-cell-role="th">ETS/MinTrace_method-mint_shrink</th> +</tr> +<tr class="odd"> +<th data-quarto-table-cell-role="th">unique_id</th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td data-quarto-table-cell-role="th">Australia</td> +<td>2015-01-01</td> +<td>34.799496</td> +<td>34.933891</td> +<td>34.927244</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">Australia</td> +<td>2015-04-01</td> +<td>35.192638</td> +<td>35.473560</td> +<td>35.440861</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">Australia</td> +<td>2015-07-01</td> +<td>35.188217</td> +<td>35.687363</td> +<td>35.476427</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">Australia</td> +<td>2015-10-01</td> +<td>35.888626</td> +<td>36.010685</td> +<td>35.946153</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">Australia</td> +<td>2016-01-01</td> +<td>36.045437</td> +<td>36.400101</td> +<td>36.244707</td> +</tr> +</tbody> +</table> + +</div> +</div> +</div> +</section> +<section id="evaluation" class="level2"> +<h2 class="anchored" data-anchor-id="evaluation">4. Evaluation</h2> +<p>The <code>HierarchicalForecast</code> package includes the <a href="https://Nixtla.github.io/hierarchicalforecast/evaluation.html#hierarchicalevaluation"><code>HierarchicalEvaluation</code></a> class to evaluate the different hierarchies and also is capable of compute scaled metrics compared to a benchmark model.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb18"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> hierarchicalforecast.evaluation <span class="im">import</span> HierarchicalEvaluation</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb19"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> mase(y, y_hat, y_insample, seasonality<span class="op">=</span><span class="dv">4</span>):</span> +<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a> errors <span class="op">=</span> np.mean(np.<span class="bu">abs</span>(y <span class="op">-</span> y_hat), axis<span class="op">=</span><span class="dv">1</span>)</span> +<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a> scale <span class="op">=</span> np.mean(np.<span class="bu">abs</span>(y_insample[:, seasonality:] <span class="op">-</span> y_insample[:, :<span class="op">-</span>seasonality]), axis<span class="op">=</span><span class="dv">1</span>)</span> +<span id="cb19-4"><a href="#cb19-4" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> np.mean(errors <span class="op">/</span> scale)</span> +<span id="cb19-5"><a href="#cb19-5" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb19-6"><a href="#cb19-6" aria-hidden="true" tabindex="-1"></a>eval_tags <span class="op">=</span> {}</span> +<span id="cb19-7"><a href="#cb19-7" aria-hidden="true" tabindex="-1"></a>eval_tags[<span class="st">'Total'</span>] <span class="op">=</span> tags[<span class="st">'Country'</span>]</span> +<span id="cb19-8"><a href="#cb19-8" aria-hidden="true" tabindex="-1"></a>eval_tags[<span class="st">'State'</span>] <span class="op">=</span> tags[<span class="st">'Country/State'</span>]</span> +<span id="cb19-9"><a href="#cb19-9" aria-hidden="true" tabindex="-1"></a>eval_tags[<span class="st">'Legal status'</span>] <span class="op">=</span> tags[<span class="st">'Country/Legal'</span>]</span> +<span id="cb19-10"><a href="#cb19-10" aria-hidden="true" tabindex="-1"></a>eval_tags[<span class="st">'Gender'</span>] <span class="op">=</span> tags[<span class="st">'Country/Gender'</span>]</span> +<span id="cb19-11"><a href="#cb19-11" aria-hidden="true" tabindex="-1"></a>eval_tags[<span class="st">'Bottom'</span>] <span class="op">=</span> tags[<span class="st">'Country/State/Gender/Legal'</span>]</span> +<span id="cb19-12"><a href="#cb19-12" aria-hidden="true" tabindex="-1"></a>eval_tags[<span class="st">'All series'</span>] <span class="op">=</span> np.concatenate(<span class="bu">list</span>(tags.values()))</span> +<span id="cb19-13"><a href="#cb19-13" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb19-14"><a href="#cb19-14" aria-hidden="true" tabindex="-1"></a>evaluator <span class="op">=</span> HierarchicalEvaluation(evaluators<span class="op">=</span>[mase])</span> +<span id="cb19-15"><a href="#cb19-15" aria-hidden="true" tabindex="-1"></a>evaluation <span class="op">=</span> evaluator.evaluate(</span> +<span id="cb19-16"><a href="#cb19-16" aria-hidden="true" tabindex="-1"></a> Y_hat_df<span class="op">=</span>Y_rec_df, Y_test_df<span class="op">=</span>Y_test_df,</span> +<span id="cb19-17"><a href="#cb19-17" aria-hidden="true" tabindex="-1"></a> tags<span class="op">=</span>eval_tags,</span> +<span id="cb19-18"><a href="#cb19-18" aria-hidden="true" tabindex="-1"></a> Y_df<span class="op">=</span>Y_train_df</span> +<span id="cb19-19"><a href="#cb19-19" aria-hidden="true" tabindex="-1"></a>)</span> +<span id="cb19-20"><a href="#cb19-20" aria-hidden="true" tabindex="-1"></a>evaluation <span class="op">=</span> evaluation.reset_index().drop(columns<span class="op">=</span><span class="st">'metric'</span>).drop(<span class="dv">0</span>).set_index(<span class="st">'level'</span>)</span> +<span id="cb19-21"><a href="#cb19-21" aria-hidden="true" tabindex="-1"></a>evaluation.columns <span class="op">=</span> [<span class="st">'Base'</span>, <span class="st">'BottomUp'</span>, <span class="st">'MinTrace(mint_shrink)'</span>]</span> +<span id="cb19-22"><a href="#cb19-22" aria-hidden="true" tabindex="-1"></a>evaluation.applymap(<span class="st">'</span><span class="sc">{:.2f}</span><span class="st">'</span>.<span class="bu">format</span>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<div> + + +<table class="dataframe table table-sm table-striped small" data-quarto-postprocess="true" data-border="1"> +<thead> +<tr class="header"> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th">Base</th> +<th data-quarto-table-cell-role="th">BottomUp</th> +<th data-quarto-table-cell-role="th">MinTrace(mint_shrink)</th> +</tr> +<tr class="odd"> +<th data-quarto-table-cell-role="th">level</th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td data-quarto-table-cell-role="th">Total</td> +<td>1.36</td> +<td>1.02</td> +<td>1.16</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">State</td> +<td>1.54</td> +<td>1.57</td> +<td>1.61</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">Legal status</td> +<td>2.40</td> +<td>2.50</td> +<td>2.40</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">Gender</td> +<td>1.08</td> +<td>0.81</td> +<td>0.95</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">Bottom</td> +<td>2.17</td> +<td>2.17</td> +<td>2.16</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">All series</td> +<td>2.00</td> +<td>2.00</td> +<td>2.00</td> +</tr> +</tbody> +</table> + +</div> +</div> +</div> +<section id="fable-comparison" class="level3"> +<h3 class="anchored" data-anchor-id="fable-comparison">Fable Comparison</h3> +<p>Observe that we can recover the results reported by the <a href="https://otexts.com/fpp3/prison.html">Forecasting: Principles and Practice</a> book. The original results were calculated using the R package <a href="https://github.com/tidyverts/fable">fable</a>.</p> +<div class="quarto-figure quarto-figure-center"> +<figure class="figure"> +<p><img src="./imgs/AustralianPrisonPopulation-results-fable.png" class="img-fluid figure-img"></p> +<figcaption class="figure-caption">Fableās reconciliation results</figcaption> +</figure> +</div> +</section> +<section id="references" class="level3"> +<h3 class="anchored" data-anchor-id="references">References</h3> +<ul> +<li><a href="https://otexts.com/fpp3/hierarchical.html">Hyndman, R.J., & Athanasopoulos, G. (2021). āForecasting: principles and practice, 3rd edition: Chapter 11: Forecasting hierarchical and grouped series.ā. OTexts: Melbourne, Australia. OTexts.com/fpp3 Accessed on July 2022.</a></li> +<li><a href="https://cran.r-project.org/web/packages/hts/index.html">Rob Hyndman, Alan Lee, Earo Wang, Shanika Wickramasuriya, and Maintainer Earo Wang (2021). āhts: Hierarchical and Grouped Time Seriesā. URL https://CRAN.R-project.org/package=hts. R package version 0.3.1.</a></li> +<li><a href="https://CRAN.R-project.org/package=fable">Mitchell OāHara-Wild, Rob Hyndman, Earo Wang, Gabriel Caceres, Tim-Gunnar Hensel, and Timothy Hyndman (2021). āfable: Forecasting Models for Tidy Time Seriesā. URL https://CRAN.R-project.org/package=fable. R package version 6.0.2.</a></li> +</ul> + + +</section> +</section> + +<p>If you find the code useful, please ā us on <a href="https://github.com/nixtla/hierarchicalforecast">Github</a></p></main> <!-- /main --> +<script id="quarto-html-after-body" type="application/javascript"> +window.document.addEventListener("DOMContentLoaded", function (event) { + const toggleBodyColorMode = (bsSheetEl) => { + const mode = bsSheetEl.getAttribute("data-mode"); + const bodyEl = window.document.querySelector("body"); + if (mode === "dark") { + bodyEl.classList.add("quarto-dark"); + bodyEl.classList.remove("quarto-light"); + } else { + bodyEl.classList.add("quarto-light"); + bodyEl.classList.remove("quarto-dark"); + } + } + const toggleBodyColorPrimary = () => { + const bsSheetEl = window.document.querySelector("link#quarto-bootstrap"); + if (bsSheetEl) { + toggleBodyColorMode(bsSheetEl); + } + } + toggleBodyColorPrimary(); + const icon = "ī§"; + const anchorJS = new window.AnchorJS(); + anchorJS.options = { + placement: 'right', + icon: icon + }; + anchorJS.add('.anchored'); + const isCodeAnnotation = (el) => { + for (const clz of el.classList) { + if (clz.startsWith('code-annotation-')) { + return true; + } + } + return false; + } + const clipboard = new window.ClipboardJS('.code-copy-button', { + text: function(trigger) { + const codeEl = trigger.previousElementSibling.cloneNode(true); + for (const childEl of codeEl.children) { + if (isCodeAnnotation(childEl)) { + childEl.remove(); + } + } + return codeEl.innerText; + } + }); + clipboard.on('success', function(e) { + // button target + const button = e.trigger; + // don't keep focus + button.blur(); + // flash "checked" + button.classList.add('code-copy-button-checked'); + var currentTitle = button.getAttribute("title"); + button.setAttribute("title", "Copied!"); + let tooltip; + if (window.bootstrap) { + button.setAttribute("data-bs-toggle", "tooltip"); + button.setAttribute("data-bs-placement", "left"); + button.setAttribute("data-bs-title", "Copied!"); + tooltip = new bootstrap.Tooltip(button, + { trigger: "manual", + customClass: "code-copy-button-tooltip", + offset: [0, -8]}); + tooltip.show(); + } + setTimeout(function() { + if (tooltip) { + tooltip.hide(); + button.removeAttribute("data-bs-title"); + button.removeAttribute("data-bs-toggle"); + button.removeAttribute("data-bs-placement"); + } + button.setAttribute("title", currentTitle); + button.classList.remove('code-copy-button-checked'); + }, 1000); + // clear code selection + e.clearSelection(); + }); + function tippyHover(el, contentFn) { + const config = { + allowHTML: true, + content: contentFn, + maxWidth: 500, + delay: 100, + arrow: false, + appendTo: function(el) { + return el.parentElement; + }, + interactive: true, + interactiveBorder: 10, + theme: 'quarto', + placement: 'bottom-start' + }; + window.tippy(el, config); + } + const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]'); + for (var i=0; i<noterefs.length; i++) { + const ref = noterefs[i]; + tippyHover(ref, function() { + // use id or data attribute instead here + let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href'); + try { href = new URL(href).hash; } catch {} + const id = href.replace(/^#\/?/, ""); + const note = window.document.getElementById(id); + return note.innerHTML; + }); + } + let selectedAnnoteEl; + const selectorForAnnotation = ( cell, annotation) => { + let cellAttr = 'data-code-cell="' + cell + '"'; + let lineAttr = 'data-code-annotation="' + annotation + '"'; + const selector = 'span[' + cellAttr + '][' + lineAttr + ']'; + return selector; + } + const selectCodeLines = (annoteEl) => { + const doc = window.document; + const targetCell = annoteEl.getAttribute("data-target-cell"); + const targetAnnotation = annoteEl.getAttribute("data-target-annotation"); + const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation)); + const lines = annoteSpan.getAttribute("data-code-lines").split(","); + const lineIds = lines.map((line) => { + return targetCell + "-" + line; + }) + let top = null; + let height = null; + let parent = null; + if (lineIds.length > 0) { + //compute the position of the single el (top and bottom and make a div) + const el = window.document.getElementById(lineIds[0]); + top = el.offsetTop; + height = el.offsetHeight; + parent = el.parentElement.parentElement; + if (lineIds.length > 1) { + const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]); + const bottom = lastEl.offsetTop + lastEl.offsetHeight; + height = bottom - top; + } + if (top !== null && height !== null && parent !== null) { + // cook up a div (if necessary) and position it + let div = window.document.getElementById("code-annotation-line-highlight"); + if (div === null) { + div = window.document.createElement("div"); + div.setAttribute("id", "code-annotation-line-highlight"); + div.style.position = 'absolute'; + parent.appendChild(div); + } + div.style.top = top - 2 + "px"; + div.style.height = height + 4 + "px"; + let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter"); + if (gutterDiv === null) { + gutterDiv = window.document.createElement("div"); + gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter"); + gutterDiv.style.position = 'absolute'; + const codeCell = window.document.getElementById(targetCell); + const gutter = codeCell.querySelector('.code-annotation-gutter'); + gutter.appendChild(gutterDiv); + } + gutterDiv.style.top = top - 2 + "px"; + gutterDiv.style.height = height + 4 + "px"; + } + selectedAnnoteEl = annoteEl; + } + }; + const unselectCodeLines = () => { + const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"]; + elementsIds.forEach((elId) => { + const div = window.document.getElementById(elId); + if (div) { + div.remove(); + } + }); + selectedAnnoteEl = undefined; + }; + // Attach click handler to the DT + const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); + for (const annoteDlNode of annoteDls) { + annoteDlNode.addEventListener('click', (event) => { + const clickedEl = event.target; + if (clickedEl !== selectedAnnoteEl) { + unselectCodeLines(); + const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active'); + if (activeEl) { + activeEl.classList.remove('code-annotation-active'); + } + selectCodeLines(clickedEl); + clickedEl.classList.add('code-annotation-active'); + } else { + // Unselect the line + unselectCodeLines(); + clickedEl.classList.remove('code-annotation-active'); + } + }); + } + const findCites = (el) => { + const parentEl = el.parentElement; + if (parentEl) { + const cites = parentEl.dataset.cites; + if (cites) { + return { + el, + cites: cites.split(' ') + }; + } else { + return findCites(el.parentElement) + } + } else { + return undefined; + } + }; + var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]'); + for (var i=0; i<bibliorefs.length; i++) { + const ref = bibliorefs[i]; + const citeInfo = findCites(ref); + if (citeInfo) { + tippyHover(citeInfo.el, function() { + var popup = window.document.createElement('div'); + citeInfo.cites.forEach(function(cite) { + var citeDiv = window.document.createElement('div'); + citeDiv.classList.add('hanging-indent'); + citeDiv.classList.add('csl-entry'); + var biblioDiv = window.document.getElementById('ref-' + cite); + if (biblioDiv) { + citeDiv.innerHTML = biblioDiv.innerHTML; + } + popup.appendChild(citeDiv); + }); + return popup.innerHTML; + }); + } + } +}); +</script> +</div> <!-- /content --> + + + +</body></html> \ No newline at end of file diff --git a/examples/hierarchicalforecast-gluonts.html b/examples/hierarchicalforecast-gluonts.html new file mode 100644 index 00000000..7626f719 --- /dev/null +++ b/examples/hierarchicalforecast-gluonts.html @@ -0,0 +1,1468 @@ +<!DOCTYPE html> +<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head> + +<meta charset="utf-8"> +<meta name="generator" content="quarto-1.3.450"> + +<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes"> + + +<title>hierarchicalforecast - GluonTS</title> +<style> +code{white-space: pre-wrap;} +span.smallcaps{font-variant: small-caps;} +div.columns{display: flex; gap: min(4vw, 1.5em);} +div.column{flex: auto; overflow-x: auto;} +div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;} +ul.task-list{list-style: none;} +ul.task-list li input[type="checkbox"] { + width: 0.8em; + margin: 0 0.8em 0.2em -1em; /* quarto-specific, see https://github.com/quarto-dev/quarto-cli/issues/4556 */ + vertical-align: middle; +} +/* CSS for syntax highlighting */ +pre > code.sourceCode { white-space: pre; position: relative; } +pre > code.sourceCode > span { display: inline-block; line-height: 1.25; } +pre > code.sourceCode > span:empty { height: 1.2em; } +.sourceCode { overflow: visible; } +code.sourceCode > span { color: inherit; text-decoration: inherit; } +div.sourceCode { margin: 1em 0; } +pre.sourceCode { margin: 0; } +@media screen { +div.sourceCode { overflow: auto; } +} +@media print { +pre > code.sourceCode { white-space: pre-wrap; } +pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; } +} +pre.numberSource code + { counter-reset: source-line 0; } +pre.numberSource code > span + { position: relative; left: -4em; counter-increment: source-line; } +pre.numberSource code > span > a:first-child::before + { content: counter(source-line); + position: relative; left: -1em; text-align: right; vertical-align: baseline; + border: none; display: inline-block; + -webkit-touch-callout: none; -webkit-user-select: none; + -khtml-user-select: none; -moz-user-select: none; + -ms-user-select: none; user-select: none; + padding: 0 4px; width: 4em; + } +pre.numberSource { margin-left: 3em; padding-left: 4px; } +div.sourceCode + { } +@media screen { +pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; } +} +</style> + + +<script src="../site_libs/quarto-nav/quarto-nav.js"></script> +<script src="../site_libs/quarto-nav/headroom.min.js"></script> +<script src="../site_libs/clipboard/clipboard.min.js"></script> +<script src="../site_libs/quarto-search/autocomplete.umd.js"></script> +<script src="../site_libs/quarto-search/fuse.min.js"></script> +<script src="../site_libs/quarto-search/quarto-search.js"></script> +<meta name="quarto:offset" content="../"> +<link href="../favicon_png.png" rel="icon" type="image/png"> +<script src="../site_libs/quarto-html/quarto.js"></script> +<script src="../site_libs/quarto-html/popper.min.js"></script> +<script src="../site_libs/quarto-html/tippy.umd.min.js"></script> +<script src="../site_libs/quarto-html/anchor.min.js"></script> +<link href="../site_libs/quarto-html/tippy.css" rel="stylesheet"> +<link href="../site_libs/quarto-html/quarto-syntax-highlighting.css" rel="stylesheet" id="quarto-text-highlighting-styles"> +<script src="../site_libs/bootstrap/bootstrap.min.js"></script> +<link href="../site_libs/bootstrap/bootstrap-icons.css" rel="stylesheet"> +<link href="../site_libs/bootstrap/bootstrap.min.css" rel="stylesheet" id="quarto-bootstrap" data-mode="light"> +<script id="quarto-search-options" type="application/json">{ + "location": "navbar", + "copy-button": false, + "collapse-after": 3, + "panel-placement": "end", + "type": "overlay", + "limit": 20, + "language": { + "search-no-results-text": "No results", + "search-matching-documents-text": "matching documents", + "search-copy-link-title": "Copy link to search", + "search-hide-matches-text": "Hide additional matches", + "search-more-match-text": "more match in this document", + "search-more-matches-text": "more matches in this document", + "search-clear-button-title": "Clear", + "search-detached-cancel-button-title": "Cancel", + "search-submit-button-title": "Submit", + "search-label": "Search" + } +}</script> +<script async="" src="https://www.googletagmanager.com/gtag/js?id=G-NXJNCVR18L"></script> + +<script type="text/javascript"> + +window.dataLayer = window.dataLayer || []; +function gtag(){dataLayer.push(arguments);} +gtag('js', new Date()); +gtag('config', 'G-NXJNCVR18L', { 'anonymize_ip': true}); +</script> +<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js" integrity="sha512-c3Nl8+7g4LMSTdrm621y7kf9v3SDPnhxLNhcjFJbKECVnmZHTdo+IRO05sNLTH/D3vA6u1X32ehoLC7WFVdheg==" crossorigin="anonymous"></script> +<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js" integrity="sha512-bLT0Qm9VnAYZDflyKcBaQ2gg0hSYNQrJ8RilYldYQ1FxQYoCLtUjuuRuZo+fjqhx/qtq/1itJ0C2ejDxltZVFg==" crossorigin="anonymous"></script> +<script type="application/javascript">define('jquery', [],function() {return window.jQuery;})</script> + + <script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script> + <script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml-full.js" type="text/javascript"></script> + +<link rel="stylesheet" href="../styles.css"> +<meta property="og:title" content="hierarchicalforecast - GluonTS"> +<meta property="og:description" content=""> +<meta property="og:image" content="https://colab.research.google.com/assets/colab-badge.svg"> +<meta property="og:site-name" content="hierarchicalforecast"> +<meta name="twitter:title" content="hierarchicalforecast - GluonTS"> +<meta name="twitter:description" content=""> +<meta name="twitter:image" content="https://colab.research.google.com/assets/colab-badge.svg"> +<meta name="twitter:card" content="summary_large_image"> +</head> + +<body class="nav-sidebar floating nav-fixed"> + +<div id="quarto-search-results"></div> + <header id="quarto-header" class="headroom fixed-top"> + <nav class="navbar navbar-expand-lg navbar-dark "> + <div class="navbar-container container-fluid"> + <div class="navbar-brand-container"> + <a class="navbar-brand" href="../index.html"> + <span class="navbar-title">hierarchicalforecast</span> + </a> + </div> + <div id="quarto-search" class="" title="Search"></div> + <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + <span class="navbar-toggler-icon"></span> +</button> + <div class="collapse navbar-collapse" id="navbarCollapse"> + <ul class="navbar-nav navbar-nav-scroll me-auto"> + <li class="nav-item"> + <a class="nav-link active" href="../examples/tourismsmall.html" rel="" target="" aria-current="page"> + <span class="menu-text">Get Started</span></a> + </li> + <li class="nav-item dropdown "> + <a class="nav-link dropdown-toggle" href="#" id="nav-menu-nixtlaverse" role="button" data-bs-toggle="dropdown" aria-expanded="false" rel="" target=""> + <span class="menu-text">NixtlaVerse</span> + </a> + <ul class="dropdown-menu" aria-labelledby="nav-menu-nixtlaverse"> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/mlforecast" rel="" target=""> + <span class="dropdown-text">MLForecast š¤</span></a> + </li> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/neuralforecast" rel="" target=""> + <span class="dropdown-text">NeuralForecast š§ </span></a> + </li> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/statsforecast" rel="" target=""> + <span class="dropdown-text">StatsForecast ā”ļø</span></a> + </li> + </ul> + </li> + <li class="nav-item dropdown "> + <a class="nav-link dropdown-toggle" href="#" id="nav-menu-help" role="button" data-bs-toggle="dropdown" aria-expanded="false" rel="" target=""> + <span class="menu-text">Help</span> + </a> + <ul class="dropdown-menu" aria-labelledby="nav-menu-help"> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/hierarchicalforecast/issues/new/choose" rel="" target=""><i class="bi bi-bug" role="img"> +</i> + <span class="dropdown-text">Report an Issue</span></a> + </li> + <li> + <a class="dropdown-item" href="https://join.slack.com/t/nixtlacommunity/shared_invite/zt-1kd5m5db7-7OOfy0xVNf1PcvCiAPWvPw" rel="" target=""><i class="bi bi-chat-right-text" role="img"> +</i> + <span class="dropdown-text">Join our Slack</span></a> + </li> + </ul> + </li> +</ul> + <ul class="navbar-nav navbar-nav-scroll ms-auto"> + <li class="nav-item compact"> + <a class="nav-link" href="https://github.com/nixtla/hierarchicalforecast" rel="" target=""><i class="bi bi-github" role="img"> +</i> + <span class="menu-text"></span></a> + </li> + <li class="nav-item compact"> + <a class="nav-link" href="https://twitter.com/nixtlainc" rel="" target=""><i class="bi bi-twitter" role="img" aria-label="Nixtla Twitter"> +</i> + <span class="menu-text"></span></a> + </li> +</ul> + <div class="quarto-navbar-tools"> +</div> + </div> <!-- /navcollapse --> + </div> <!-- /container-fluid --> + </nav> + <nav class="quarto-secondary-nav"> + <div class="container-fluid d-flex"> + <button type="button" class="quarto-btn-toggle btn" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + <i class="bi bi-layout-text-sidebar-reverse"></i> + </button> + <nav class="quarto-page-breadcrumbs" aria-label="breadcrumb"><ol class="breadcrumb"><li class="breadcrumb-item">Tutorials</li><li class="breadcrumb-item"><a href="../examples/hierarchicalforecast-gluonts.html">ML Forecast Reconciliation</a></li><li class="breadcrumb-item"><a href="../examples/hierarchicalforecast-gluonts.html">GluonTS</a></li></ol></nav> + <a class="flex-grow-1" role="button" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + </a> + </div> + </nav> +</header> +<!-- content --> +<div id="quarto-content" class="quarto-container page-columns page-rows-contents page-layout-article page-navbar"> +<!-- sidebar --> + <nav id="quarto-sidebar" class="sidebar collapse collapse-horizontal sidebar-navigation floating overflow-auto"> + <div class="sidebar-menu-container"> + <ul class="list-unstyled mt-1"> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../index.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Hierarchical Forecast š</span></a> + </div> +</li> + <li class="px-0"><hr class="sidebar-divider hi "></li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-1" aria-expanded="false"> + <span class="menu-text">Getting Started</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-1" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-1" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/installation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Install</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/tourismsmall.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Reconciliation Quick Start</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/introduction.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Introduction</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-2" aria-expanded="true"> + <span class="menu-text">Tutorials</span></a> + <a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-2" aria-expanded="true" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-2" class="collapse list-unstyled sidebar-section depth1 show"> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-3" aria-expanded="false"> + <span class="menu-text">Point Reconciliation</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-3" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-3" class="collapse list-unstyled sidebar-section depth2 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Geographical Aggregation (Tourism)</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australianprisonpopulation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Geographical Aggregation (Prison Population)</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/nonnegativereconciliation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Non-Negative MinTrace</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-4" aria-expanded="false"> + <span class="menu-text">Probabilistic Reconciliation</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-4" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-4" class="collapse list-unstyled sidebar-section depth2 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Normality</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism-bootstraped-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Bootstrap</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism-permbu-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">PERMBU</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/tourismlarge-evaluation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Probabilistic Forecast Evaluation</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-5" aria-expanded="true"> + <span class="menu-text">ML Forecast Reconciliation</span></a> + <a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-5" aria-expanded="true" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-5" class="collapse list-unstyled sidebar-section depth2 show"> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/hierarchicalforecast-gluonts.html" class="sidebar-item-text sidebar-link active"> + <span class="menu-text">GluonTS</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/mlframeworksexample.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Neural/MLForecast</span></a> + </div> +</li> + </ul> + </li> + </ul> + </li> + <li class="sidebar-item"> + <span class="menu-text">Methods</span> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-6" aria-expanded="false"> + <span class="menu-text">API Reference</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-6" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-6" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../core.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Core </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../methods.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Reconciliation Methods </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../probabilistic_methods.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Probabilistic Methods </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../evaluation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Hierarchical Evaluation</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../utils.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Aggregation/Visualization Utils</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-7" aria-expanded="false"> + <span class="menu-text">Community</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-7" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-7" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item"> + <span class="menu-text">Contributing</span> + </li> + </ul> + </li> + </ul> + </div> +</nav> +<div id="quarto-sidebar-glass" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass"></div> +<!-- margin-sidebar --> + <div id="quarto-margin-sidebar" class="sidebar margin-sidebar"> + <nav id="TOC" role="doc-toc" class="toc-active"> + <h2 id="toc-title">On this page</h2> + + <ul> + <li><a href="#installing-packages" id="toc-installing-packages" class="nav-link active" data-scroll-target="#installing-packages">1. Installing packages</a></li> + <li><a href="#load-hierarchical-dataset" id="toc-load-hierarchical-dataset" class="nav-link" data-scroll-target="#load-hierarchical-dataset">2. Load hierarchical dataset</a></li> + <li><a href="#fit-and-predict-model" id="toc-fit-and-predict-model" class="nav-link" data-scroll-target="#fit-and-predict-model">3. Fit and Predict Model</a></li> + <li><a href="#reconciliation" id="toc-reconciliation" class="nav-link" data-scroll-target="#reconciliation">4. Reconciliation</a></li> + <li><a href="#evaluation" id="toc-evaluation" class="nav-link" data-scroll-target="#evaluation">5. Evaluation</a></li> + </ul> +<div class="toc-actions"><div><i class="bi bi-github"></i></div><div class="action-links"><p><a href="https://github.com/Nixtla/hierarchicalforecast/issues/new" class="toc-action">Report an issue</a></p></div></div></nav> + </div> +<!-- main --> +<main class="content" id="quarto-document-content"> + +<header id="title-block-header" class="quarto-title-block default"> +<div class="quarto-title"> +<h1 class="title">GluonTS</h1> +</div> + + + +<div class="quarto-title-meta"> + + + + + </div> + + +</header> + +<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! --> +<p>This example notebook demonstrates the compatibility of HierarchicalForecastās reconciliation methods with popular machine-learning libraries, specifically <a href="https://ts.gluon.ai/stable/">GluonTS</a>.</p> +<p>The notebook utilizes the GluonTS DeepAREstimator to create base forecasts for the TourismLarge Hierarchical Dataset. We make the base forecasts compatible with HierarchicalForecastās reconciliation functions via the <a href="https://Nixtla.github.io/hierarchicalforecast/utils.html#samples_to_quantiles_df"><code>samples_to_quantiles_df</code></a> utility function that transforms GluonTSā output forecasts into a compatible data frame format. After that, we use HierarchicalForecast to reconcile the base predictions.</p> +<p><strong>References</strong><br> - <a href="https://www.sciencedirect.com/science/article/pii/S0169207019301888">David Salinas, Valentin Flunkert, Jan Gasthaus, Tim Januschowski (2020). āDeepAR: Probabilistic forecasting with autoregressive recurrent networksā. International Journal of Forecasting.</a><br> - <a href="https://www.jmlr.org/papers/v21/19-820.html">Alexander Alexandrov et. al (2020). āGluonTS: Probabilistic and Neural Time Series Modeling in Pythonā. Journal of Machine Learning Research.</a><br></p> +<p>You can run these experiments using CPU or GPU with Google Colab.</p> +<p><a href="https://colab.research.google.com/github/Nixtla/hierarchicalforecast/blob/main/nbs/examples/HierarchicalForecast-GluonTS.ipynb" target="_parent"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"></a></p> +<section id="installing-packages" class="level2"> +<h2 class="anchored" data-anchor-id="installing-packages">1. Installing packages</h2> +<div class="cell"> +<div class="sourceCode cell-code" id="cb1"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="op">!</span>pip install mxnet<span class="op">-</span>cu112</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb2"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> mxnet <span class="im">as</span> mx</span> +<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="cf">assert</span> mx.context.num_gpus()<span class="op">></span><span class="dv">0</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb3"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="op">!</span>pip install gluonts</span> +<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="op">!</span>pip install datasetsforecast</span> +<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="op">!</span>pip install git<span class="op">+</span>https:<span class="op">//</span>github.com<span class="op">/</span>Nixtla<span class="op">/</span>hierarchicalforecast.git</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb4"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> numpy <span class="im">as</span> np</span> +<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> pandas <span class="im">as</span> pd</span> +<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> datasetsforecast.hierarchical <span class="im">import</span> HierarchicalData</span> +<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> gluonts.mx.trainer <span class="im">import</span> Trainer</span> +<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> gluonts.dataset.pandas <span class="im">import</span> PandasDataset</span> +<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> gluonts.mx.model.deepar <span class="im">import</span> DeepAREstimator</span> +<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> hierarchicalforecast.methods <span class="im">import</span> BottomUp, MinTrace</span> +<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> hierarchicalforecast.core <span class="im">import</span> HierarchicalReconciliation</span> +<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> hierarchicalforecast.evaluation <span class="im">import</span> scaled_crps</span> +<span id="cb4-13"><a href="#cb4-13" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> hierarchicalforecast.utils <span class="im">import</span> samples_to_quantiles_df</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-stderr"> +<pre><code>/usr/local/lib/python3.10/dist-packages/gluonts/json.py:101: UserWarning: Using `json`-module for json-handling. Consider installing one of `orjson`, `ujson` to speed up serialization and deserialization. + warnings.warn(</code></pre> +</div> +</div> +</section> +<section id="load-hierarchical-dataset" class="level2"> +<h2 class="anchored" data-anchor-id="load-hierarchical-dataset">2. Load hierarchical dataset</h2> +<p>This detailed Australian Tourism Dataset comes from the National Visitor Survey, managed by the Tourism Research Australia, it is composed of 555 monthly series from 1998 to 2016, it is organized geographically, and purpose of travel. The natural geographical hierarchy comprises seven states, divided further in 27 zones and 76 regions. The purpose of travel categories are holiday, visiting friends and relatives (VFR), business and other. The MinT (Wickramasuriya et al., 2019), among other hierarchical forecasting studies has used the dataset it in the past. The dataset can be accessed in the <a href="https://robjhyndman.com/publications/mint/">MinT reconciliation webpage</a>, although other sources are available.</p> +<table class="table"> +<colgroup> +<col style="width: 25%"> +<col style="width: 25%"> +<col style="width: 25%"> +<col style="width: 25%"> +</colgroup> +<thead> +<tr class="header"> +<th>Geographical Division</th> +<th>Number of series per division</th> +<th>Number of series per purpose</th> +<th>Total</th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td>Australia</td> +<td>1</td> +<td>4</td> +<td>5</td> +</tr> +<tr class="even"> +<td>States</td> +<td>7</td> +<td>28</td> +<td>35</td> +</tr> +<tr class="odd"> +<td>Zones</td> +<td>27</td> +<td>108</td> +<td>135</td> +</tr> +<tr class="even"> +<td>Regions</td> +<td>76</td> +<td>304</td> +<td>380</td> +</tr> +<tr class="odd"> +<td>Total</td> +<td>111</td> +<td>444</td> +<td>555</td> +</tr> +</tbody> +</table> +<div class="cell"> +<div class="sourceCode cell-code" id="cb6"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a>dataset <span class="op">=</span> <span class="st">'TourismLarge'</span></span> +<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a>Y_df, S_df, tags <span class="op">=</span> HierarchicalData.load(directory <span class="op">=</span> <span class="st">"./data"</span>, group<span class="op">=</span>dataset)</span> +<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a>Y_df[<span class="st">'ds'</span>] <span class="op">=</span> pd.to_datetime(Y_df[<span class="st">'ds'</span>])</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb7"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> sort_hier_df(Y_df, S_df):</span> +<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a> <span class="co"># sorts unique_id lexicographically</span></span> +<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a> Y_df.unique_id <span class="op">=</span> Y_df.unique_id.astype(<span class="st">'category'</span>)</span> +<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a> Y_df.unique_id <span class="op">=</span> Y_df.unique_id.cat.set_categories(S_df.index)</span> +<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a> Y_df <span class="op">=</span> Y_df.sort_values(by<span class="op">=</span>[<span class="st">'unique_id'</span>, <span class="st">'ds'</span>])</span> +<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> Y_df</span> +<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a>Y_df <span class="op">=</span> sort_hier_df(Y_df, S_df)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb8"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a>horizon <span class="op">=</span> <span class="dv">12</span></span> +<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a>Y_test_df <span class="op">=</span> Y_df.groupby(<span class="st">'unique_id'</span>).tail(horizon)</span> +<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a>Y_train_df <span class="op">=</span> Y_df.drop(Y_test_df.index)</span> +<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a>Y_train_df</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> + + <div id="df-87ea6e86-85b6-4549-b2b8-2a40b880d3ab"> + <div class="colab-df-container"> + <div> + + +<table class="dataframe table table-sm table-striped small" data-quarto-postprocess="true" data-border="1"> +<thead> +<tr class="header"> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th">unique_id</th> +<th data-quarto-table-cell-role="th">ds</th> +<th data-quarto-table-cell-role="th">y</th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td data-quarto-table-cell-role="th">0</td> +<td>TotalAll</td> +<td>1998-01-01</td> +<td>45151.071280</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">1</td> +<td>TotalAll</td> +<td>1998-02-01</td> +<td>17294.699551</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">2</td> +<td>TotalAll</td> +<td>1998-03-01</td> +<td>20725.114184</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">3</td> +<td>TotalAll</td> +<td>1998-04-01</td> +<td>25388.612353</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">4</td> +<td>TotalAll</td> +<td>1998-05-01</td> +<td>20330.035211</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">...</td> +<td>...</td> +<td>...</td> +<td>...</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">126523</td> +<td>GBDOth</td> +<td>2015-08-01</td> +<td>17.683774</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">126524</td> +<td>GBDOth</td> +<td>2015-09-01</td> +<td>0.000000</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">126525</td> +<td>GBDOth</td> +<td>2015-10-01</td> +<td>0.000000</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">126526</td> +<td>GBDOth</td> +<td>2015-11-01</td> +<td>0.000000</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">126527</td> +<td>GBDOth</td> +<td>2015-12-01</td> +<td>0.000000</td> +</tr> +</tbody> +</table> + + +<p>119880 rows Ć 3 columns</p> +</div> + <button class="colab-df-convert" onclick="convertToInteractive('df-87ea6e86-85b6-4549-b2b8-2a40b880d3ab')" title="Convert this dataframe to an interactive table." style="display:none;"> + + <svg xmlns="http://www.w3.org/2000/svg" height="24px" viewbox="0 0 24 24" width="24px"> + <path d="M0 0h24v24H0V0z" fill="none"></path> + <path d="M18.56 5.44l.94 2.06.94-2.06 2.06-.94-2.06-.94-.94-2.06-.94 2.06-2.06.94zm-11 1L8.5 8.5l.94-2.06 2.06-.94-2.06-.94L8.5 2.5l-.94 2.06-2.06.94zm10 10l.94 2.06.94-2.06 2.06-.94-2.06-.94-.94-2.06-.94 2.06-2.06.94z"></path><path d="M17.41 7.96l-1.37-1.37c-.4-.4-.92-.59-1.43-.59-.52 0-1.04.2-1.43.59L10.3 9.45l-7.72 7.72c-.78.78-.78 2.05 0 2.83L4 21.41c.39.39.9.59 1.41.59.51 0 1.02-.2 1.41-.59l7.78-7.78 2.81-2.81c.8-.78.8-2.07 0-2.86zM5.41 20L4 18.59l7.72-7.72 1.47 1.35L5.41 20z"></path> + </svg> + </button> + + <style> + .colab-df-container { + display:flex; + flex-wrap:wrap; + gap: 12px; + } + + .colab-df-convert { + background-color: #E8F0FE; + border: none; + border-radius: 50%; + cursor: pointer; + display: none; + fill: #1967D2; + height: 32px; + padding: 0 0 0 0; + width: 32px; + } + + .colab-df-convert:hover { + background-color: #E2EBFA; + box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 1px 3px 1px rgba(60, 64, 67, 0.15); + fill: #174EA6; + } + + [theme=dark] .colab-df-convert { + background-color: #3B4455; + fill: #D2E3FC; + } + + [theme=dark] .colab-df-convert:hover { + background-color: #434B5C; + box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.15); + filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.3)); + fill: #FFFFFF; + } + </style> + + <script> + const buttonEl = + document.querySelector('#df-87ea6e86-85b6-4549-b2b8-2a40b880d3ab button.colab-df-convert'); + buttonEl.style.display = + google.colab.kernel.accessAllowed ? 'block' : 'none'; + + async function convertToInteractive(key) { + const element = document.querySelector('#df-87ea6e86-85b6-4549-b2b8-2a40b880d3ab'); + const dataTable = + await google.colab.kernel.invokeFunction('convertToInteractive', + [key], {}); + if (!dataTable) return; + + const docLinkHtml = 'Like what you see? Visit the ' + + '<a target="_blank" href=https://colab.research.google.com/notebooks/data_table.ipynb>data table notebook</a>' + + ' to learn more about interactive tables.'; + element.innerHTML = ''; + dataTable['output_type'] = 'display_data'; + await google.colab.output.renderOutput(dataTable, element); + const docLink = document.createElement('div'); + docLink.innerHTML = docLinkHtml; + element.appendChild(docLink); + } + </script> + </div> + </div> + +</div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb9"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a>ds <span class="op">=</span> PandasDataset.from_long_dataframe(Y_train_df, target<span class="op">=</span><span class="st">"y"</span>, item_id<span class="op">=</span><span class="st">"unique_id"</span>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +</section> +<section id="fit-and-predict-model" class="level2"> +<h2 class="anchored" data-anchor-id="fit-and-predict-model">3. Fit and Predict Model</h2> +<div class="cell"> +<div class="sourceCode cell-code" id="cb10"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a>estimator <span class="op">=</span> DeepAREstimator(</span> +<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a> freq<span class="op">=</span><span class="st">"M"</span>,</span> +<span id="cb10-3"><a href="#cb10-3" aria-hidden="true" tabindex="-1"></a> prediction_length<span class="op">=</span>horizon,</span> +<span id="cb10-4"><a href="#cb10-4" aria-hidden="true" tabindex="-1"></a> trainer<span class="op">=</span>Trainer(ctx <span class="op">=</span> mx.context.gpu(),</span> +<span id="cb10-5"><a href="#cb10-5" aria-hidden="true" tabindex="-1"></a> epochs<span class="op">=</span><span class="dv">20</span>),</span> +<span id="cb10-6"><a href="#cb10-6" aria-hidden="true" tabindex="-1"></a>)</span> +<span id="cb10-7"><a href="#cb10-7" aria-hidden="true" tabindex="-1"></a>predictor <span class="op">=</span> estimator.train(ds)</span> +<span id="cb10-8"><a href="#cb10-8" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb10-9"><a href="#cb10-9" aria-hidden="true" tabindex="-1"></a>forecast_it <span class="op">=</span> predictor.predict(ds, num_samples<span class="op">=</span><span class="dv">1000</span>)</span> +<span id="cb10-10"><a href="#cb10-10" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb10-11"><a href="#cb10-11" aria-hidden="true" tabindex="-1"></a>forecasts <span class="op">=</span> <span class="bu">list</span>(forecast_it)</span> +<span id="cb10-12"><a href="#cb10-12" aria-hidden="true" tabindex="-1"></a>forecasts <span class="op">=</span> np.array([arr.samples <span class="cf">for</span> arr <span class="kw">in</span> forecasts])</span> +<span id="cb10-13"><a href="#cb10-13" aria-hidden="true" tabindex="-1"></a>forecasts.shape</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-stderr"> +<pre><code>100%|āāāāāāāāāā| 50/50 [00:11<00:00, 4.39it/s, epoch=1/20, avg_epoch_loss=5.35] +100%|āāāāāāāāāā| 50/50 [00:05<00:00, 8.75it/s, epoch=2/20, avg_epoch_loss=5.22] +100%|āāāāāāāāāā| 50/50 [00:03<00:00, 14.41it/s, epoch=3/20, avg_epoch_loss=5.17] +100%|āāāāāāāāāā| 50/50 [00:02<00:00, 20.76it/s, epoch=4/20, avg_epoch_loss=5.02] +100%|āāāāāāāāāā| 50/50 [00:02<00:00, 19.27it/s, epoch=5/20, avg_epoch_loss=5.05] +100%|āāāāāāāāāā| 50/50 [00:04<00:00, 11.52it/s, epoch=6/20, avg_epoch_loss=5.12] +100%|āāāāāāāāāā| 50/50 [00:03<00:00, 16.59it/s, epoch=7/20, avg_epoch_loss=4.97] +100%|āāāāāāāāāā| 50/50 [00:03<00:00, 16.27it/s, epoch=8/20, avg_epoch_loss=4.97] +100%|āāāāāāāāāā| 50/50 [00:02<00:00, 19.96it/s, epoch=9/20, avg_epoch_loss=5.11] +100%|āāāāāāāāāā| 50/50 [00:04<00:00, 11.36it/s, epoch=10/20, avg_epoch_loss=4.97] +100%|āāāāāāāāāā| 50/50 [00:03<00:00, 16.62it/s, epoch=11/20, avg_epoch_loss=5.05] +100%|āāāāāāāāāā| 50/50 [00:02<00:00, 17.76it/s, epoch=12/20, avg_epoch_loss=5.04] +100%|āāāāāāāāāā| 50/50 [00:02<00:00, 21.56it/s, epoch=13/20, avg_epoch_loss=4.99] +100%|āāāāāāāāāā| 50/50 [00:02<00:00, 20.64it/s, epoch=14/20, avg_epoch_loss=5.03] +100%|āāāāāāāāāā| 50/50 [00:03<00:00, 13.22it/s, epoch=15/20, avg_epoch_loss=4.97] +100%|āāāāāāāāāā| 50/50 [00:02<00:00, 17.79it/s, epoch=16/20, avg_epoch_loss=4.95] +100%|āāāāāāāāāā| 50/50 [00:02<00:00, 18.29it/s, epoch=17/20, avg_epoch_loss=5.02] +100%|āāāāāāāāāā| 50/50 [00:02<00:00, 17.73it/s, epoch=18/20, avg_epoch_loss=5.02] +100%|āāāāāāāāāā| 50/50 [00:02<00:00, 19.10it/s, epoch=19/20, avg_epoch_loss=5.02] +100%|āāāāāāāāāā| 50/50 [00:03<00:00, 13.29it/s, epoch=20/20, avg_epoch_loss=5]</code></pre> +</div> +<div class="cell-output cell-output-display"> +<pre><code>(555, 1000, 12)</code></pre> +</div> +</div> +</section> +<section id="reconciliation" class="level2"> +<h2 class="anchored" data-anchor-id="reconciliation">4. Reconciliation</h2> +<div class="cell"> +<div class="sourceCode cell-code" id="cb13"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a>level <span class="op">=</span> np.arange(<span class="dv">1</span>, <span class="dv">100</span>, <span class="dv">2</span>)</span> +<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a><span class="co">#transform the output of DeepAREstimator to a form that is compatible with HierarchicalForecast</span></span> +<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a>quantiles, forecast_df <span class="op">=</span> samples_to_quantiles_df(samples<span class="op">=</span>forecasts, </span> +<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a> unique_ids<span class="op">=</span>S_df.index, </span> +<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a> dates<span class="op">=</span>Y_test_df[<span class="st">'ds'</span>].unique(), </span> +<span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a> level<span class="op">=</span>level,</span> +<span id="cb13-8"><a href="#cb13-8" aria-hidden="true" tabindex="-1"></a> model_name<span class="op">=</span><span class="st">'DeepAREstimator'</span>)</span> +<span id="cb13-9"><a href="#cb13-9" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb13-10"><a href="#cb13-10" aria-hidden="true" tabindex="-1"></a><span class="co">#reconcile forecasts</span></span> +<span id="cb13-11"><a href="#cb13-11" aria-hidden="true" tabindex="-1"></a>reconcilers <span class="op">=</span> [</span> +<span id="cb13-12"><a href="#cb13-12" aria-hidden="true" tabindex="-1"></a> BottomUp(),</span> +<span id="cb13-13"><a href="#cb13-13" aria-hidden="true" tabindex="-1"></a> MinTrace(<span class="st">'ols'</span>)</span> +<span id="cb13-14"><a href="#cb13-14" aria-hidden="true" tabindex="-1"></a>]</span> +<span id="cb13-15"><a href="#cb13-15" aria-hidden="true" tabindex="-1"></a>hrec <span class="op">=</span> HierarchicalReconciliation(reconcilers<span class="op">=</span>reconcilers)</span> +<span id="cb13-16"><a href="#cb13-16" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb13-17"><a href="#cb13-17" aria-hidden="true" tabindex="-1"></a>forecast_rec <span class="op">=</span> hrec.reconcile(Y_hat_df<span class="op">=</span>forecast_df, S<span class="op">=</span>S_df, tags<span class="op">=</span>tags, level<span class="op">=</span>level)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb14"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a>forecast_rec</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> + + <div id="df-c5007f63-f723-4e34-8e99-f26f5aa035b0"> + <div class="colab-df-container"> + <div> + + +<table class="dataframe table table-sm table-striped small" data-quarto-postprocess="true" data-border="1"> +<thead> +<tr class="header"> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th">ds</th> +<th data-quarto-table-cell-role="th">DeepAREstimator</th> +<th data-quarto-table-cell-role="th">DeepAREstimator-median</th> +<th data-quarto-table-cell-role="th">DeepAREstimator-lo-99</th> +<th data-quarto-table-cell-role="th">DeepAREstimator-lo-97</th> +<th data-quarto-table-cell-role="th">DeepAREstimator-lo-95</th> +<th data-quarto-table-cell-role="th">DeepAREstimator-lo-93</th> +<th data-quarto-table-cell-role="th">DeepAREstimator-lo-91</th> +<th data-quarto-table-cell-role="th">DeepAREstimator-lo-89</th> +<th data-quarto-table-cell-role="th">DeepAREstimator-lo-87</th> +<th data-quarto-table-cell-role="th">...</th> +<th data-quarto-table-cell-role="th">DeepAREstimator/MinTrace_method-ols-hi-81</th> +<th data-quarto-table-cell-role="th">DeepAREstimator/MinTrace_method-ols-hi-83</th> +<th data-quarto-table-cell-role="th">DeepAREstimator/MinTrace_method-ols-hi-85</th> +<th data-quarto-table-cell-role="th">DeepAREstimator/MinTrace_method-ols-hi-87</th> +<th data-quarto-table-cell-role="th">DeepAREstimator/MinTrace_method-ols-hi-89</th> +<th data-quarto-table-cell-role="th">DeepAREstimator/MinTrace_method-ols-hi-91</th> +<th data-quarto-table-cell-role="th">DeepAREstimator/MinTrace_method-ols-hi-93</th> +<th data-quarto-table-cell-role="th">DeepAREstimator/MinTrace_method-ols-hi-95</th> +<th data-quarto-table-cell-role="th">DeepAREstimator/MinTrace_method-ols-hi-97</th> +<th data-quarto-table-cell-role="th">DeepAREstimator/MinTrace_method-ols-hi-99</th> +</tr> +<tr class="odd"> +<th data-quarto-table-cell-role="th">unique_id</th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td data-quarto-table-cell-role="th">TotalAll</td> +<td>2016-01-01</td> +<td>43165.929688</td> +<td>43002.058594</td> +<td>27712.297979</td> +<td>30371.243516</td> +<td>32741.458740</td> +<td>33305.429492</td> +<td>34446.465957</td> +<td>35164.380410</td> +<td>35732.592422</td> +<td>...</td> +<td>48703.132046</td> +<td>48956.752480</td> +<td>49233.843836</td> +<td>49540.743219</td> +<td>49886.826218</td> +<td>50286.877928</td> +<td>50766.394577</td> +<td>51375.717577</td> +<td>52240.506366</td> +<td>53910.351214</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">TotalAll</td> +<td>2016-02-01</td> +<td>20326.796875</td> +<td>20469.210938</td> +<td>13156.550879</td> +<td>15086.488257</td> +<td>15738.457031</td> +<td>16134.386343</td> +<td>16696.160010</td> +<td>16828.676436</td> +<td>17139.442129</td> +<td>...</td> +<td>22902.635244</td> +<td>23019.412684</td> +<td>23146.997118</td> +<td>23288.306411</td> +<td>23447.657478</td> +<td>23631.857993</td> +<td>23852.647485</td> +<td>24133.205242</td> +<td>24531.390118</td> +<td>25300.256426</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">TotalAll</td> +<td>2016-03-01</td> +<td>24362.203125</td> +<td>24237.250977</td> +<td>17340.837197</td> +<td>18470.071582</td> +<td>19132.180615</td> +<td>19658.168945</td> +<td>19974.223359</td> +<td>20339.483584</td> +<td>20519.382959</td> +<td>...</td> +<td>26759.166634</td> +<td>26873.896338</td> +<td>26999.243530</td> +<td>27138.074912</td> +<td>27294.631699</td> +<td>27475.602189</td> +<td>27692.520055</td> +<td>27968.158127</td> +<td>28359.360682</td> +<td>29114.744632</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">TotalAll</td> +<td>2016-04-01</td> +<td>29131.662109</td> +<td>29236.008789</td> +<td>19923.623740</td> +<td>21814.112246</td> +<td>22685.987500</td> +<td>23350.113418</td> +<td>23721.056963</td> +<td>24168.286201</td> +<td>24513.198066</td> +<td>...</td> +<td>32277.209370</td> +<td>32427.584386</td> +<td>32591.875632</td> +<td>32773.840464</td> +<td>32979.037796</td> +<td>33216.233913</td> +<td>33500.545877</td> +<td>33861.821798</td> +<td>34374.566871</td> +<td>35364.640665</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">TotalAll</td> +<td>2016-05-01</td> +<td>22587.779297</td> +<td>22638.541016</td> +<td>14453.285947</td> +<td>16236.985869</td> +<td>17163.251807</td> +<td>17894.046758</td> +<td>18559.204453</td> +<td>18789.053066</td> +<td>19055.381455</td> +<td>...</td> +<td>25400.976716</td> +<td>25532.984575</td> +<td>25677.208902</td> +<td>25836.948122</td> +<td>26017.082170</td> +<td>26225.306596</td> +<td>26474.892029</td> +<td>26792.040860</td> +<td>27242.158045</td> +<td>28111.301901</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">GBDOth</td> +<td>2016-08-01</td> +<td>-0.300811</td> +<td>-0.316894</td> +<td>-2.994549</td> +<td>-2.208182</td> +<td>-2.005075</td> +<td>-1.725068</td> +<td>-1.620723</td> +<td>-1.501304</td> +<td>-1.355108</td> +<td>...</td> +<td>27.151595</td> +<td>28.293141</td> +<td>29.540330</td> +<td>30.921685</td> +<td>32.479405</td> +<td>34.280039</td> +<td>36.438344</td> +<td>39.180908</td> +<td>43.073324</td> +<td>50.589300</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">GBDOth</td> +<td>2016-09-01</td> +<td>-0.089410</td> +<td>-0.079164</td> +<td>-2.981229</td> +<td>-2.356738</td> +<td>-1.812428</td> +<td>-1.499515</td> +<td>-1.365453</td> +<td>-1.199702</td> +<td>-1.120727</td> +<td>...</td> +<td>24.912080</td> +<td>26.035044</td> +<td>27.261932</td> +<td>28.620801</td> +<td>30.153165</td> +<td>31.924489</td> +<td>34.047662</td> +<td>36.745584</td> +<td>40.574640</td> +<td>47.968273</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">GBDOth</td> +<td>2016-10-01</td> +<td>-0.196041</td> +<td>-0.207104</td> +<td>-2.829650</td> +<td>-2.270969</td> +<td>-1.674091</td> +<td>-1.289834</td> +<td>-1.153728</td> +<td>-1.078916</td> +<td>-1.029915</td> +<td>...</td> +<td>25.423958</td> +<td>26.550973</td> +<td>27.782287</td> +<td>29.146059</td> +<td>30.683952</td> +<td>32.461666</td> +<td>34.592499</td> +<td>37.300154</td> +<td>41.143025</td> +<td>48.563331</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">GBDOth</td> +<td>2016-11-01</td> +<td>-0.315826</td> +<td>-0.274183</td> +<td>-2.461571</td> +<td>-1.829249</td> +<td>-1.535889</td> +<td>-1.329642</td> +<td>-1.260961</td> +<td>-1.134465</td> +<td>-1.007276</td> +<td>...</td> +<td>25.125960</td> +<td>26.257991</td> +<td>27.494784</td> +<td>28.864625</td> +<td>30.409361</td> +<td>32.194986</td> +<td>34.335301</td> +<td>37.055005</td> +<td>40.914977</td> +<td>48.368305</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">GBDOth</td> +<td>2016-12-01</td> +<td>-0.291579</td> +<td>-0.268462</td> +<td>-3.987842</td> +<td>-2.078746</td> +<td>-1.619226</td> +<td>-1.385310</td> +<td>-1.253607</td> +<td>-1.156472</td> +<td>-1.092625</td> +<td>...</td> +<td>26.216098</td> +<td>27.310535</td> +<td>28.506255</td> +<td>29.830604</td> +<td>31.324041</td> +<td>33.050366</td> +<td>35.119603</td> +<td>37.748987</td> +<td>41.480772</td> +<td>48.686579</td> +</tr> +</tbody> +</table> + + +<p>6660 rows Ć 305 columns</p> +</div> + <button class="colab-df-convert" onclick="convertToInteractive('df-c5007f63-f723-4e34-8e99-f26f5aa035b0')" title="Convert this dataframe to an interactive table." style="display:none;"> + + <svg xmlns="http://www.w3.org/2000/svg" height="24px" viewbox="0 0 24 24" width="24px"> + <path d="M0 0h24v24H0V0z" fill="none"></path> + <path d="M18.56 5.44l.94 2.06.94-2.06 2.06-.94-2.06-.94-.94-2.06-.94 2.06-2.06.94zm-11 1L8.5 8.5l.94-2.06 2.06-.94-2.06-.94L8.5 2.5l-.94 2.06-2.06.94zm10 10l.94 2.06.94-2.06 2.06-.94-2.06-.94-.94-2.06-.94 2.06-2.06.94z"></path><path d="M17.41 7.96l-1.37-1.37c-.4-.4-.92-.59-1.43-.59-.52 0-1.04.2-1.43.59L10.3 9.45l-7.72 7.72c-.78.78-.78 2.05 0 2.83L4 21.41c.39.39.9.59 1.41.59.51 0 1.02-.2 1.41-.59l7.78-7.78 2.81-2.81c.8-.78.8-2.07 0-2.86zM5.41 20L4 18.59l7.72-7.72 1.47 1.35L5.41 20z"></path> + </svg> + </button> + + <style> + .colab-df-container { + display:flex; + flex-wrap:wrap; + gap: 12px; + } + + .colab-df-convert { + background-color: #E8F0FE; + border: none; + border-radius: 50%; + cursor: pointer; + display: none; + fill: #1967D2; + height: 32px; + padding: 0 0 0 0; + width: 32px; + } + + .colab-df-convert:hover { + background-color: #E2EBFA; + box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 1px 3px 1px rgba(60, 64, 67, 0.15); + fill: #174EA6; + } + + [theme=dark] .colab-df-convert { + background-color: #3B4455; + fill: #D2E3FC; + } + + [theme=dark] .colab-df-convert:hover { + background-color: #434B5C; + box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.15); + filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.3)); + fill: #FFFFFF; + } + </style> + + <script> + const buttonEl = + document.querySelector('#df-c5007f63-f723-4e34-8e99-f26f5aa035b0 button.colab-df-convert'); + buttonEl.style.display = + google.colab.kernel.accessAllowed ? 'block' : 'none'; + + async function convertToInteractive(key) { + const element = document.querySelector('#df-c5007f63-f723-4e34-8e99-f26f5aa035b0'); + const dataTable = + await google.colab.kernel.invokeFunction('convertToInteractive', + [key], {}); + if (!dataTable) return; + + const docLinkHtml = 'Like what you see? Visit the ' + + '<a target="_blank" href=https://colab.research.google.com/notebooks/data_table.ipynb>data table notebook</a>' + + ' to learn more about interactive tables.'; + element.innerHTML = ''; + dataTable['output_type'] = 'display_data'; + await google.colab.output.renderOutput(dataTable, element); + const docLink = document.createElement('div'); + docLink.innerHTML = docLinkHtml; + element.appendChild(docLink); + } + </script> + </div> + </div> + +</div> +</div> +</section> +<section id="evaluation" class="level2"> +<h2 class="anchored" data-anchor-id="evaluation">5. Evaluation</h2> +<p>To evaluate we use a scaled variation of the CRPS, as proposed by Rangapuram (2021), to measure the accuracy of predicted quantiles <code>y_hat</code> compared to the observation <code>y</code>.</p> +<p><span class="math display">\[ \mathrm{sCRPS}(\hat{F}_{\tau}, \mathbf{y}_{\tau}) = \frac{2}{N} \sum_{i} +\int^{1}_{0} +\frac{\mathrm{QL}(\hat{F}_{i,\tau}, y_{i,\tau})_{q}}{\sum_{i} | y_{i,\tau} |} dq \]</span></p> +<p>As you can see, HierarchicalForecast results improve on the results of specialized algorithms like <a href="https://proceedings.mlr.press/v139/rangapuram21a.html">HierE2E</a>.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb15"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a>rec_model_names <span class="op">=</span> [<span class="st">'DeepAREstimator/MinTrace_method-ols'</span>, <span class="st">'DeepAREstimator/BottomUp'</span>]</span> +<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a>quantiles <span class="op">=</span> np.array(quantiles[<span class="dv">1</span>:]) <span class="co">#remove first quantile (median)</span></span> +<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a>n_quantiles <span class="op">=</span> <span class="bu">len</span>(quantiles)</span> +<span id="cb15-5"><a href="#cb15-5" aria-hidden="true" tabindex="-1"></a>n_series <span class="op">=</span> <span class="bu">len</span>(S_df)</span> +<span id="cb15-6"><a href="#cb15-6" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb15-7"><a href="#cb15-7" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> name <span class="kw">in</span> rec_model_names:</span> +<span id="cb15-8"><a href="#cb15-8" aria-hidden="true" tabindex="-1"></a> quantile_columns <span class="op">=</span> [col <span class="cf">for</span> col <span class="kw">in</span> forecast_rec.columns <span class="cf">if</span> (name<span class="op">+</span><span class="st">'-'</span>) <span class="kw">in</span> col]</span> +<span id="cb15-9"><a href="#cb15-9" aria-hidden="true" tabindex="-1"></a> y_rec <span class="op">=</span> forecast_rec[quantile_columns].values </span> +<span id="cb15-10"><a href="#cb15-10" aria-hidden="true" tabindex="-1"></a> y_test <span class="op">=</span> Y_test_df[<span class="st">'y'</span>].values</span> +<span id="cb15-11"><a href="#cb15-11" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb15-12"><a href="#cb15-12" aria-hidden="true" tabindex="-1"></a> y_rec <span class="op">=</span> y_rec.reshape(n_series, horizon, n_quantiles)</span> +<span id="cb15-13"><a href="#cb15-13" aria-hidden="true" tabindex="-1"></a> y_test <span class="op">=</span> y_test.reshape(n_series, horizon)</span> +<span id="cb15-14"><a href="#cb15-14" aria-hidden="true" tabindex="-1"></a> scrps <span class="op">=</span> scaled_crps(y<span class="op">=</span>y_test, y_hat<span class="op">=</span>y_rec, quantiles<span class="op">=</span>quantiles)</span> +<span id="cb15-15"><a href="#cb15-15" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"</span><span class="sc">{:<40}</span><span class="st"> </span><span class="sc">{:.5f}</span><span class="st">"</span>.<span class="bu">format</span>(name<span class="op">+</span><span class="st">":"</span>, scrps))</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-stdout"> +<pre><code>DeepAREstimator/MinTrace_method-ols: 0.12632 +DeepAREstimator/BottomUp: 0.13933</code></pre> +</div> +</div> + + +</section> + +<p>If you find the code useful, please ā us on <a href="https://github.com/nixtla/hierarchicalforecast">Github</a></p></main> <!-- /main --> +<script id="quarto-html-after-body" type="application/javascript"> +window.document.addEventListener("DOMContentLoaded", function (event) { + const toggleBodyColorMode = (bsSheetEl) => { + const mode = bsSheetEl.getAttribute("data-mode"); + const bodyEl = window.document.querySelector("body"); + if (mode === "dark") { + bodyEl.classList.add("quarto-dark"); + bodyEl.classList.remove("quarto-light"); + } else { + bodyEl.classList.add("quarto-light"); + bodyEl.classList.remove("quarto-dark"); + } + } + const toggleBodyColorPrimary = () => { + const bsSheetEl = window.document.querySelector("link#quarto-bootstrap"); + if (bsSheetEl) { + toggleBodyColorMode(bsSheetEl); + } + } + toggleBodyColorPrimary(); + const icon = "ī§"; + const anchorJS = new window.AnchorJS(); + anchorJS.options = { + placement: 'right', + icon: icon + }; + anchorJS.add('.anchored'); + const isCodeAnnotation = (el) => { + for (const clz of el.classList) { + if (clz.startsWith('code-annotation-')) { + return true; + } + } + return false; + } + const clipboard = new window.ClipboardJS('.code-copy-button', { + text: function(trigger) { + const codeEl = trigger.previousElementSibling.cloneNode(true); + for (const childEl of codeEl.children) { + if (isCodeAnnotation(childEl)) { + childEl.remove(); + } + } + return codeEl.innerText; + } + }); + clipboard.on('success', function(e) { + // button target + const button = e.trigger; + // don't keep focus + button.blur(); + // flash "checked" + button.classList.add('code-copy-button-checked'); + var currentTitle = button.getAttribute("title"); + button.setAttribute("title", "Copied!"); + let tooltip; + if (window.bootstrap) { + button.setAttribute("data-bs-toggle", "tooltip"); + button.setAttribute("data-bs-placement", "left"); + button.setAttribute("data-bs-title", "Copied!"); + tooltip = new bootstrap.Tooltip(button, + { trigger: "manual", + customClass: "code-copy-button-tooltip", + offset: [0, -8]}); + tooltip.show(); + } + setTimeout(function() { + if (tooltip) { + tooltip.hide(); + button.removeAttribute("data-bs-title"); + button.removeAttribute("data-bs-toggle"); + button.removeAttribute("data-bs-placement"); + } + button.setAttribute("title", currentTitle); + button.classList.remove('code-copy-button-checked'); + }, 1000); + // clear code selection + e.clearSelection(); + }); + function tippyHover(el, contentFn) { + const config = { + allowHTML: true, + content: contentFn, + maxWidth: 500, + delay: 100, + arrow: false, + appendTo: function(el) { + return el.parentElement; + }, + interactive: true, + interactiveBorder: 10, + theme: 'quarto', + placement: 'bottom-start' + }; + window.tippy(el, config); + } + const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]'); + for (var i=0; i<noterefs.length; i++) { + const ref = noterefs[i]; + tippyHover(ref, function() { + // use id or data attribute instead here + let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href'); + try { href = new URL(href).hash; } catch {} + const id = href.replace(/^#\/?/, ""); + const note = window.document.getElementById(id); + return note.innerHTML; + }); + } + let selectedAnnoteEl; + const selectorForAnnotation = ( cell, annotation) => { + let cellAttr = 'data-code-cell="' + cell + '"'; + let lineAttr = 'data-code-annotation="' + annotation + '"'; + const selector = 'span[' + cellAttr + '][' + lineAttr + ']'; + return selector; + } + const selectCodeLines = (annoteEl) => { + const doc = window.document; + const targetCell = annoteEl.getAttribute("data-target-cell"); + const targetAnnotation = annoteEl.getAttribute("data-target-annotation"); + const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation)); + const lines = annoteSpan.getAttribute("data-code-lines").split(","); + const lineIds = lines.map((line) => { + return targetCell + "-" + line; + }) + let top = null; + let height = null; + let parent = null; + if (lineIds.length > 0) { + //compute the position of the single el (top and bottom and make a div) + const el = window.document.getElementById(lineIds[0]); + top = el.offsetTop; + height = el.offsetHeight; + parent = el.parentElement.parentElement; + if (lineIds.length > 1) { + const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]); + const bottom = lastEl.offsetTop + lastEl.offsetHeight; + height = bottom - top; + } + if (top !== null && height !== null && parent !== null) { + // cook up a div (if necessary) and position it + let div = window.document.getElementById("code-annotation-line-highlight"); + if (div === null) { + div = window.document.createElement("div"); + div.setAttribute("id", "code-annotation-line-highlight"); + div.style.position = 'absolute'; + parent.appendChild(div); + } + div.style.top = top - 2 + "px"; + div.style.height = height + 4 + "px"; + let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter"); + if (gutterDiv === null) { + gutterDiv = window.document.createElement("div"); + gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter"); + gutterDiv.style.position = 'absolute'; + const codeCell = window.document.getElementById(targetCell); + const gutter = codeCell.querySelector('.code-annotation-gutter'); + gutter.appendChild(gutterDiv); + } + gutterDiv.style.top = top - 2 + "px"; + gutterDiv.style.height = height + 4 + "px"; + } + selectedAnnoteEl = annoteEl; + } + }; + const unselectCodeLines = () => { + const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"]; + elementsIds.forEach((elId) => { + const div = window.document.getElementById(elId); + if (div) { + div.remove(); + } + }); + selectedAnnoteEl = undefined; + }; + // Attach click handler to the DT + const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); + for (const annoteDlNode of annoteDls) { + annoteDlNode.addEventListener('click', (event) => { + const clickedEl = event.target; + if (clickedEl !== selectedAnnoteEl) { + unselectCodeLines(); + const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active'); + if (activeEl) { + activeEl.classList.remove('code-annotation-active'); + } + selectCodeLines(clickedEl); + clickedEl.classList.add('code-annotation-active'); + } else { + // Unselect the line + unselectCodeLines(); + clickedEl.classList.remove('code-annotation-active'); + } + }); + } + const findCites = (el) => { + const parentEl = el.parentElement; + if (parentEl) { + const cites = parentEl.dataset.cites; + if (cites) { + return { + el, + cites: cites.split(' ') + }; + } else { + return findCites(el.parentElement) + } + } else { + return undefined; + } + }; + var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]'); + for (var i=0; i<bibliorefs.length; i++) { + const ref = bibliorefs[i]; + const citeInfo = findCites(ref); + if (citeInfo) { + tippyHover(citeInfo.el, function() { + var popup = window.document.createElement('div'); + citeInfo.cites.forEach(function(cite) { + var citeDiv = window.document.createElement('div'); + citeDiv.classList.add('hanging-indent'); + citeDiv.classList.add('csl-entry'); + var biblioDiv = window.document.getElementById('ref-' + cite); + if (biblioDiv) { + citeDiv.innerHTML = biblioDiv.innerHTML; + } + popup.appendChild(citeDiv); + }); + return popup.innerHTML; + }); + } + } +}); +</script> +</div> <!-- /content --> + + + +</body></html> \ No newline at end of file diff --git a/examples/imgs/AustralianDomesticTourism-results-fable.png b/examples/imgs/AustralianDomesticTourism-results-fable.png new file mode 100644 index 00000000..15f437d0 Binary files /dev/null and b/examples/imgs/AustralianDomesticTourism-results-fable.png differ diff --git a/examples/imgs/AustralianPrisonPopulation-results-fable.png b/examples/imgs/AustralianPrisonPopulation-results-fable.png new file mode 100644 index 00000000..fc4f988c Binary files /dev/null and b/examples/imgs/AustralianPrisonPopulation-results-fable.png differ diff --git a/examples/imgs/hierarchical_motivation1.png b/examples/imgs/hierarchical_motivation1.png new file mode 100644 index 00000000..1504f766 Binary files /dev/null and b/examples/imgs/hierarchical_motivation1.png differ diff --git a/examples/imgs/hierarchical_motivation2.png b/examples/imgs/hierarchical_motivation2.png new file mode 100644 index 00000000..1be4525d Binary files /dev/null and b/examples/imgs/hierarchical_motivation2.png differ diff --git a/examples/index.html b/examples/index.html new file mode 100644 index 00000000..05789cba --- /dev/null +++ b/examples/index.html @@ -0,0 +1,748 @@ +<!DOCTYPE html> +<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head> + +<meta charset="utf-8"> +<meta name="generator" content="quarto-1.3.450"> + +<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes"> + + +<title>hierarchicalforecast - Tutorials</title> +<style> +code{white-space: pre-wrap;} +span.smallcaps{font-variant: small-caps;} +div.columns{display: flex; gap: min(4vw, 1.5em);} +div.column{flex: auto; overflow-x: auto;} +div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;} +ul.task-list{list-style: none;} +ul.task-list li input[type="checkbox"] { + width: 0.8em; + margin: 0 0.8em 0.2em -1em; /* quarto-specific, see https://github.com/quarto-dev/quarto-cli/issues/4556 */ + vertical-align: middle; +} +</style> + + +<script src="../site_libs/quarto-nav/quarto-nav.js"></script> +<script src="../site_libs/quarto-nav/headroom.min.js"></script> +<script src="../site_libs/clipboard/clipboard.min.js"></script> +<script src="../site_libs/quarto-search/autocomplete.umd.js"></script> +<script src="../site_libs/quarto-search/fuse.min.js"></script> +<script src="../site_libs/quarto-search/quarto-search.js"></script> +<meta name="quarto:offset" content="../"> +<link href="../favicon_png.png" rel="icon" type="image/png"> +<script src="../site_libs/quarto-listing/list.min.js"></script> +<script src="../site_libs/quarto-listing/quarto-listing.js"></script> +<script src="../site_libs/quarto-html/quarto.js"></script> +<script src="../site_libs/quarto-html/popper.min.js"></script> +<script src="../site_libs/quarto-html/tippy.umd.min.js"></script> +<script src="../site_libs/quarto-html/anchor.min.js"></script> +<link href="../site_libs/quarto-html/tippy.css" rel="stylesheet"> +<link href="../site_libs/quarto-html/quarto-syntax-highlighting.css" rel="stylesheet" id="quarto-text-highlighting-styles"> +<script src="../site_libs/bootstrap/bootstrap.min.js"></script> +<link href="../site_libs/bootstrap/bootstrap-icons.css" rel="stylesheet"> +<link href="../site_libs/bootstrap/bootstrap.min.css" rel="stylesheet" id="quarto-bootstrap" data-mode="light"> +<script id="quarto-search-options" type="application/json">{ + "location": "navbar", + "copy-button": false, + "collapse-after": 3, + "panel-placement": "end", + "type": "overlay", + "limit": 20, + "language": { + "search-no-results-text": "No results", + "search-matching-documents-text": "matching documents", + "search-copy-link-title": "Copy link to search", + "search-hide-matches-text": "Hide additional matches", + "search-more-match-text": "more match in this document", + "search-more-matches-text": "more matches in this document", + "search-clear-button-title": "Clear", + "search-detached-cancel-button-title": "Cancel", + "search-submit-button-title": "Submit", + "search-label": "Search" + } +}</script> +<script> + + window.document.addEventListener("DOMContentLoaded", function (_event) { + const listingTargetEl = window.document.querySelector('#listing-listing .list'); + if (!listingTargetEl) { + // No listing discovered, do not attach. + return; + } + + const options = { + valueNames: ['listing-title',{ data: ['index'] },{ data: ['categories'] },{ data: ['listing-date-sort'] },{ data: ['listing-title-sort'] }], + + searchColumns: ["listing-title","listing-author"], + }; + + window['quarto-listings'] = window['quarto-listings'] || {}; + window['quarto-listings']['listing-listing'] = new List('listing-listing', options); + + if (window['quarto-listing-loaded']) { + window['quarto-listing-loaded'](); + } + }); + + window.addEventListener('hashchange',() => { + if (window['quarto-listing-loaded']) { + window['quarto-listing-loaded'](); + } + }) + </script> +<script async="" src="https://www.googletagmanager.com/gtag/js?id=G-NXJNCVR18L"></script> + +<script type="text/javascript"> + +window.dataLayer = window.dataLayer || []; +function gtag(){dataLayer.push(arguments);} +gtag('js', new Date()); +gtag('config', 'G-NXJNCVR18L', { 'anonymize_ip': true}); +</script> + + <script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script> + <script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml-full.js" type="text/javascript"></script> + +<link rel="stylesheet" href="../styles.css"> +<meta property="og:title" content="hierarchicalforecast - Tutorials"> +<meta property="og:description" content=""> +<meta property="og:site-name" content="hierarchicalforecast"> +<meta name="twitter:title" content="hierarchicalforecast - Tutorials"> +<meta name="twitter:description" content=""> +<meta name="twitter:card" content="summary"> +</head> + +<body class="nav-sidebar floating nav-fixed"> + +<div id="quarto-search-results"></div> + <header id="quarto-header" class="headroom fixed-top"> + <nav class="navbar navbar-expand-lg navbar-dark "> + <div class="navbar-container container-fluid"> + <div class="navbar-brand-container"> + <a class="navbar-brand" href="../index.html"> + <span class="navbar-title">hierarchicalforecast</span> + </a> + </div> + <div id="quarto-search" class="" title="Search"></div> + <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + <span class="navbar-toggler-icon"></span> +</button> + <div class="collapse navbar-collapse" id="navbarCollapse"> + <ul class="navbar-nav navbar-nav-scroll me-auto"> + <li class="nav-item"> + <a class="nav-link active" href="../examples/tourismsmall.html" rel="" target="" aria-current="page"> + <span class="menu-text">Get Started</span></a> + </li> + <li class="nav-item dropdown "> + <a class="nav-link dropdown-toggle" href="#" id="nav-menu-nixtlaverse" role="button" data-bs-toggle="dropdown" aria-expanded="false" rel="" target=""> + <span class="menu-text">NixtlaVerse</span> + </a> + <ul class="dropdown-menu" aria-labelledby="nav-menu-nixtlaverse"> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/mlforecast" rel="" target=""> + <span class="dropdown-text">MLForecast š¤</span></a> + </li> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/neuralforecast" rel="" target=""> + <span class="dropdown-text">NeuralForecast š§ </span></a> + </li> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/statsforecast" rel="" target=""> + <span class="dropdown-text">StatsForecast ā”ļø</span></a> + </li> + </ul> + </li> + <li class="nav-item dropdown "> + <a class="nav-link dropdown-toggle" href="#" id="nav-menu-help" role="button" data-bs-toggle="dropdown" aria-expanded="false" rel="" target=""> + <span class="menu-text">Help</span> + </a> + <ul class="dropdown-menu" aria-labelledby="nav-menu-help"> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/hierarchicalforecast/issues/new/choose" rel="" target=""><i class="bi bi-bug" role="img"> +</i> + <span class="dropdown-text">Report an Issue</span></a> + </li> + <li> + <a class="dropdown-item" href="https://join.slack.com/t/nixtlacommunity/shared_invite/zt-1kd5m5db7-7OOfy0xVNf1PcvCiAPWvPw" rel="" target=""><i class="bi bi-chat-right-text" role="img"> +</i> + <span class="dropdown-text">Join our Slack</span></a> + </li> + </ul> + </li> +</ul> + <ul class="navbar-nav navbar-nav-scroll ms-auto"> + <li class="nav-item compact"> + <a class="nav-link" href="https://github.com/nixtla/hierarchicalforecast" rel="" target=""><i class="bi bi-github" role="img"> +</i> + <span class="menu-text"></span></a> + </li> + <li class="nav-item compact"> + <a class="nav-link" href="https://twitter.com/nixtlainc" rel="" target=""><i class="bi bi-twitter" role="img" aria-label="Nixtla Twitter"> +</i> + <span class="menu-text"></span></a> + </li> +</ul> + <div class="quarto-navbar-tools"> +</div> + </div> <!-- /navcollapse --> + </div> <!-- /container-fluid --> + </nav> + <nav class="quarto-secondary-nav"> + <div class="container-fluid d-flex"> + <button type="button" class="quarto-btn-toggle btn" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + <i class="bi bi-layout-text-sidebar-reverse"></i> + </button> + <nav class="quarto-page-breadcrumbs" aria-label="breadcrumb"><ol class="breadcrumb"><li class="breadcrumb-item">Tutorials</li></ol></nav> + <a class="flex-grow-1" role="button" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + </a> + </div> + </nav> +</header> +<!-- content --> +<div id="quarto-content" class="quarto-container page-columns page-rows-contents page-layout-article page-navbar"> +<!-- sidebar --> + <nav id="quarto-sidebar" class="sidebar collapse collapse-horizontal sidebar-navigation floating overflow-auto"> + <div class="sidebar-menu-container"> + <ul class="list-unstyled mt-1"> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../index.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Hierarchical Forecast š</span></a> + </div> +</li> + <li class="px-0"><hr class="sidebar-divider hi "></li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-1" aria-expanded="false"> + <span class="menu-text">Getting Started</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-1" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-1" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/installation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Install</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/tourismsmall.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Reconciliation Quick Start</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/introduction.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Introduction</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-2" aria-expanded="false"> + <span class="menu-text">Tutorials</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-2" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-2" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-3" aria-expanded="false"> + <span class="menu-text">Point Reconciliation</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-3" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-3" class="collapse list-unstyled sidebar-section depth2 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Geographical Aggregation (Tourism)</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australianprisonpopulation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Geographical Aggregation (Prison Population)</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/nonnegativereconciliation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Non-Negative MinTrace</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-4" aria-expanded="false"> + <span class="menu-text">Probabilistic Reconciliation</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-4" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-4" class="collapse list-unstyled sidebar-section depth2 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Normality</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism-bootstraped-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Bootstrap</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism-permbu-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">PERMBU</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/tourismlarge-evaluation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Probabilistic Forecast Evaluation</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-5" aria-expanded="false"> + <span class="menu-text">ML Forecast Reconciliation</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-5" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-5" class="collapse list-unstyled sidebar-section depth2 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/hierarchicalforecast-gluonts.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">GluonTS</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/mlframeworksexample.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Neural/MLForecast</span></a> + </div> +</li> + </ul> + </li> + </ul> + </li> + <li class="sidebar-item"> + <span class="menu-text">Methods</span> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-6" aria-expanded="false"> + <span class="menu-text">API Reference</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-6" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-6" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../core.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Core </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../methods.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Reconciliation Methods </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../probabilistic_methods.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Probabilistic Methods </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../evaluation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Hierarchical Evaluation</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../utils.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Aggregation/Visualization Utils</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-7" aria-expanded="false"> + <span class="menu-text">Community</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-7" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-7" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item"> + <span class="menu-text">Contributing</span> + </li> + </ul> + </li> + </ul> + </div> +</nav> +<div id="quarto-sidebar-glass" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass"></div> +<!-- margin-sidebar --> + <div id="quarto-margin-sidebar" class="sidebar margin-sidebar"> + + </div> +<!-- main --> +<main class="content" id="quarto-document-content"> + +<header id="title-block-header" class="quarto-title-block default"> +<div class="quarto-title"> +<h1 class="title">Tutorials</h1> +</div> + + + +<div class="quarto-title-meta"> + + + + + </div> + + +</header> + +<p>Click through to any of these tutorials to get started with <code>HierarchicalForecast</code>ās features.</p> + + + + +<div class="quarto-listing quarto-listing-container-table" id="listing-listing"> + +<table class="quarto-listing-table table"> +<thead> +<tr> +<th> +Title +</th> +</tr> +</thead> +<tbody class="list"> +<tr data-index="0" data-listing-file-modified-sort="1696370046456" data-listing-reading-time-sort="2" data-listing-title-sort="Bootstrap" data-listing-filename-sort="AustralianDomesticTourism-Bootstraped-Intervals.ipynb"> +<td> +<a href="../examples/australiandomestictourism-bootstraped-intervals.html" class="title listing-title">Bootstrap</a> +</td> +</tr> +<tr data-index="1" data-listing-file-modified-sort="1696370046800" data-listing-reading-time-sort="3" data-listing-title-sort="Geographical Aggregation (Prison Population)" data-listing-filename-sort="AustralianPrisonPopulation.ipynb"> +<td> +<a href="../examples/australianprisonpopulation.html" class="title listing-title">Geographical Aggregation (Prison Population)</a> +</td> +</tr> +<tr data-index="2" data-listing-file-modified-sort="1696370046276" data-listing-reading-time-sort="3" data-listing-title-sort="Geographical Aggregation (Tourism)" data-listing-filename-sort="AustralianDomesticTourism.ipynb"> +<td> +<a href="../examples/australiandomestictourism.html" class="title listing-title">Geographical Aggregation (Tourism)</a> +</td> +</tr> +<tr data-index="3" data-listing-file-modified-sort="1696370046688" data-listing-reading-time-sort="4" data-listing-title-sort="GluonTS" data-listing-filename-sort="HierarchicalForecast-GluonTS.ipynb"> +<td> +<a href="../examples/hierarchicalforecast-gluonts.html" class="title listing-title">GluonTS</a> +</td> +</tr> +<tr data-index="4" data-listing-file-modified-sort="1696370046760" data-listing-reading-time-sort="1" data-listing-title-sort="Install" data-listing-filename-sort="Installation.ipynb"> +<td> +<a href="../examples/installation.html" class="title listing-title">Install</a> +</td> +</tr> +<tr data-index="5" data-listing-file-modified-sort="1696370046328" data-listing-reading-time-sort="4" data-listing-title-sort="Introduction" data-listing-filename-sort="Introduction.ipynb"> +<td> +<a href="../examples/introduction.html" class="title listing-title">Introduction</a> +</td> +</tr> +<tr data-index="6" data-listing-file-modified-sort="1696370046876" data-listing-reading-time-sort="5" data-listing-title-sort="Neural/MLForecast" data-listing-filename-sort="MLFrameworksExample.ipynb"> +<td> +<a href="../examples/mlframeworksexample.html" class="title listing-title">Neural/MLForecast</a> +</td> +</tr> +<tr data-index="7" data-listing-file-modified-sort="1696370046520" data-listing-reading-time-sort="2" data-listing-title-sort="Non-Negative MinTrace" data-listing-filename-sort="NonNegativeReconciliation.ipynb"> +<td> +<a href="../examples/nonnegativereconciliation.html" class="title listing-title">Non-Negative MinTrace</a> +</td> +</tr> +<tr data-index="8" data-listing-file-modified-sort="1696370046648" data-listing-reading-time-sort="2" data-listing-title-sort="Normality" data-listing-filename-sort="AustralianDomesticTourism-Intervals.ipynb"> +<td> +<a href="../examples/australiandomestictourism-intervals.html" class="title listing-title">Normality</a> +</td> +</tr> +<tr data-index="9" data-listing-file-modified-sort="1696370046576" data-listing-reading-time-sort="2" data-listing-title-sort="PERMBU" data-listing-filename-sort="AustralianDomesticTourism-Permbu-Intervals.ipynb"> +<td> +<a href="../examples/australiandomestictourism-permbu-intervals.html" class="title listing-title">PERMBU</a> +</td> +</tr> +<tr data-index="10" data-listing-file-modified-sort="1696370046228" data-listing-reading-time-sort="2" data-listing-title-sort="Probabilistic Forecast Evaluation" data-listing-filename-sort="TourismLarge-Evaluation.ipynb"> +<td> +<a href="../examples/tourismlarge-evaluation.html" class="title listing-title">Probabilistic Forecast Evaluation</a> +</td> +</tr> +<tr data-index="11" data-listing-file-modified-sort="1696370046728" data-listing-reading-time-sort="2" data-listing-title-sort="Reconciliation Quick Start" data-listing-filename-sort="TourismSmall.ipynb"> +<td> +<a href="../examples/tourismsmall.html" class="title listing-title">Reconciliation Quick Start</a> +</td> +</tr> +</tbody> + +</table> +<div class="listing-no-matching d-none"> +No matching items +</div> +</div><p>If you find the code useful, please ā us on <a href="https://github.com/nixtla/hierarchicalforecast">Github</a></p></main> <!-- /main --> +<script id="quarto-html-after-body" type="application/javascript"> +window.document.addEventListener("DOMContentLoaded", function (event) { + const toggleBodyColorMode = (bsSheetEl) => { + const mode = bsSheetEl.getAttribute("data-mode"); + const bodyEl = window.document.querySelector("body"); + if (mode === "dark") { + bodyEl.classList.add("quarto-dark"); + bodyEl.classList.remove("quarto-light"); + } else { + bodyEl.classList.add("quarto-light"); + bodyEl.classList.remove("quarto-dark"); + } + } + const toggleBodyColorPrimary = () => { + const bsSheetEl = window.document.querySelector("link#quarto-bootstrap"); + if (bsSheetEl) { + toggleBodyColorMode(bsSheetEl); + } + } + toggleBodyColorPrimary(); + const icon = "ī§"; + const anchorJS = new window.AnchorJS(); + anchorJS.options = { + placement: 'right', + icon: icon + }; + anchorJS.add('.anchored'); + const isCodeAnnotation = (el) => { + for (const clz of el.classList) { + if (clz.startsWith('code-annotation-')) { + return true; + } + } + return false; + } + const clipboard = new window.ClipboardJS('.code-copy-button', { + text: function(trigger) { + const codeEl = trigger.previousElementSibling.cloneNode(true); + for (const childEl of codeEl.children) { + if (isCodeAnnotation(childEl)) { + childEl.remove(); + } + } + return codeEl.innerText; + } + }); + clipboard.on('success', function(e) { + // button target + const button = e.trigger; + // don't keep focus + button.blur(); + // flash "checked" + button.classList.add('code-copy-button-checked'); + var currentTitle = button.getAttribute("title"); + button.setAttribute("title", "Copied!"); + let tooltip; + if (window.bootstrap) { + button.setAttribute("data-bs-toggle", "tooltip"); + button.setAttribute("data-bs-placement", "left"); + button.setAttribute("data-bs-title", "Copied!"); + tooltip = new bootstrap.Tooltip(button, + { trigger: "manual", + customClass: "code-copy-button-tooltip", + offset: [0, -8]}); + tooltip.show(); + } + setTimeout(function() { + if (tooltip) { + tooltip.hide(); + button.removeAttribute("data-bs-title"); + button.removeAttribute("data-bs-toggle"); + button.removeAttribute("data-bs-placement"); + } + button.setAttribute("title", currentTitle); + button.classList.remove('code-copy-button-checked'); + }, 1000); + // clear code selection + e.clearSelection(); + }); + function tippyHover(el, contentFn) { + const config = { + allowHTML: true, + content: contentFn, + maxWidth: 500, + delay: 100, + arrow: false, + appendTo: function(el) { + return el.parentElement; + }, + interactive: true, + interactiveBorder: 10, + theme: 'quarto', + placement: 'bottom-start' + }; + window.tippy(el, config); + } + const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]'); + for (var i=0; i<noterefs.length; i++) { + const ref = noterefs[i]; + tippyHover(ref, function() { + // use id or data attribute instead here + let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href'); + try { href = new URL(href).hash; } catch {} + const id = href.replace(/^#\/?/, ""); + const note = window.document.getElementById(id); + return note.innerHTML; + }); + } + let selectedAnnoteEl; + const selectorForAnnotation = ( cell, annotation) => { + let cellAttr = 'data-code-cell="' + cell + '"'; + let lineAttr = 'data-code-annotation="' + annotation + '"'; + const selector = 'span[' + cellAttr + '][' + lineAttr + ']'; + return selector; + } + const selectCodeLines = (annoteEl) => { + const doc = window.document; + const targetCell = annoteEl.getAttribute("data-target-cell"); + const targetAnnotation = annoteEl.getAttribute("data-target-annotation"); + const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation)); + const lines = annoteSpan.getAttribute("data-code-lines").split(","); + const lineIds = lines.map((line) => { + return targetCell + "-" + line; + }) + let top = null; + let height = null; + let parent = null; + if (lineIds.length > 0) { + //compute the position of the single el (top and bottom and make a div) + const el = window.document.getElementById(lineIds[0]); + top = el.offsetTop; + height = el.offsetHeight; + parent = el.parentElement.parentElement; + if (lineIds.length > 1) { + const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]); + const bottom = lastEl.offsetTop + lastEl.offsetHeight; + height = bottom - top; + } + if (top !== null && height !== null && parent !== null) { + // cook up a div (if necessary) and position it + let div = window.document.getElementById("code-annotation-line-highlight"); + if (div === null) { + div = window.document.createElement("div"); + div.setAttribute("id", "code-annotation-line-highlight"); + div.style.position = 'absolute'; + parent.appendChild(div); + } + div.style.top = top - 2 + "px"; + div.style.height = height + 4 + "px"; + let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter"); + if (gutterDiv === null) { + gutterDiv = window.document.createElement("div"); + gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter"); + gutterDiv.style.position = 'absolute'; + const codeCell = window.document.getElementById(targetCell); + const gutter = codeCell.querySelector('.code-annotation-gutter'); + gutter.appendChild(gutterDiv); + } + gutterDiv.style.top = top - 2 + "px"; + gutterDiv.style.height = height + 4 + "px"; + } + selectedAnnoteEl = annoteEl; + } + }; + const unselectCodeLines = () => { + const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"]; + elementsIds.forEach((elId) => { + const div = window.document.getElementById(elId); + if (div) { + div.remove(); + } + }); + selectedAnnoteEl = undefined; + }; + // Attach click handler to the DT + const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); + for (const annoteDlNode of annoteDls) { + annoteDlNode.addEventListener('click', (event) => { + const clickedEl = event.target; + if (clickedEl !== selectedAnnoteEl) { + unselectCodeLines(); + const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active'); + if (activeEl) { + activeEl.classList.remove('code-annotation-active'); + } + selectCodeLines(clickedEl); + clickedEl.classList.add('code-annotation-active'); + } else { + // Unselect the line + unselectCodeLines(); + clickedEl.classList.remove('code-annotation-active'); + } + }); + } + const findCites = (el) => { + const parentEl = el.parentElement; + if (parentEl) { + const cites = parentEl.dataset.cites; + if (cites) { + return { + el, + cites: cites.split(' ') + }; + } else { + return findCites(el.parentElement) + } + } else { + return undefined; + } + }; + var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]'); + for (var i=0; i<bibliorefs.length; i++) { + const ref = bibliorefs[i]; + const citeInfo = findCites(ref); + if (citeInfo) { + tippyHover(citeInfo.el, function() { + var popup = window.document.createElement('div'); + citeInfo.cites.forEach(function(cite) { + var citeDiv = window.document.createElement('div'); + citeDiv.classList.add('hanging-indent'); + citeDiv.classList.add('csl-entry'); + var biblioDiv = window.document.getElementById('ref-' + cite); + if (biblioDiv) { + citeDiv.innerHTML = biblioDiv.innerHTML; + } + popup.appendChild(citeDiv); + }); + return popup.innerHTML; + }); + } + } +}); +</script> +</div> <!-- /content --> + + + +<footer class="footer"><div class="nav-footer"><div class="nav-footer-center"><div class="toc-actions"><div><i class="bi bi-github"></i></div><div class="action-links"><p><a href="https://github.com/Nixtla/hierarchicalforecast/issues/new" class="toc-action">Report an issue</a></p></div></div></div></div></footer></body></html> \ No newline at end of file diff --git a/examples/installation.html b/examples/installation.html new file mode 100644 index 00000000..f3219460 --- /dev/null +++ b/examples/installation.html @@ -0,0 +1,710 @@ +<!DOCTYPE html> +<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head> + +<meta charset="utf-8"> +<meta name="generator" content="quarto-1.3.450"> + +<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes"> + +<meta name="description" content="Install HierachicalForecast with pip or conda"> + +<title>hierarchicalforecast - Install</title> +<style> +code{white-space: pre-wrap;} +span.smallcaps{font-variant: small-caps;} +div.columns{display: flex; gap: min(4vw, 1.5em);} +div.column{flex: auto; overflow-x: auto;} +div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;} +ul.task-list{list-style: none;} +ul.task-list li input[type="checkbox"] { + width: 0.8em; + margin: 0 0.8em 0.2em -1em; /* quarto-specific, see https://github.com/quarto-dev/quarto-cli/issues/4556 */ + vertical-align: middle; +} +/* CSS for syntax highlighting */ +pre > code.sourceCode { white-space: pre; position: relative; } +pre > code.sourceCode > span { display: inline-block; line-height: 1.25; } +pre > code.sourceCode > span:empty { height: 1.2em; } +.sourceCode { overflow: visible; } +code.sourceCode > span { color: inherit; text-decoration: inherit; } +div.sourceCode { margin: 1em 0; } +pre.sourceCode { margin: 0; } +@media screen { +div.sourceCode { overflow: auto; } +} +@media print { +pre > code.sourceCode { white-space: pre-wrap; } +pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; } +} +pre.numberSource code + { counter-reset: source-line 0; } +pre.numberSource code > span + { position: relative; left: -4em; counter-increment: source-line; } +pre.numberSource code > span > a:first-child::before + { content: counter(source-line); + position: relative; left: -1em; text-align: right; vertical-align: baseline; + border: none; display: inline-block; + -webkit-touch-callout: none; -webkit-user-select: none; + -khtml-user-select: none; -moz-user-select: none; + -ms-user-select: none; user-select: none; + padding: 0 4px; width: 4em; + } +pre.numberSource { margin-left: 3em; padding-left: 4px; } +div.sourceCode + { } +@media screen { +pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; } +} +</style> + + +<script src="../site_libs/quarto-nav/quarto-nav.js"></script> +<script src="../site_libs/quarto-nav/headroom.min.js"></script> +<script src="../site_libs/clipboard/clipboard.min.js"></script> +<script src="../site_libs/quarto-search/autocomplete.umd.js"></script> +<script src="../site_libs/quarto-search/fuse.min.js"></script> +<script src="../site_libs/quarto-search/quarto-search.js"></script> +<meta name="quarto:offset" content="../"> +<link href="../favicon_png.png" rel="icon" type="image/png"> +<script src="../site_libs/quarto-html/quarto.js"></script> +<script src="../site_libs/quarto-html/popper.min.js"></script> +<script src="../site_libs/quarto-html/tippy.umd.min.js"></script> +<script src="../site_libs/quarto-html/anchor.min.js"></script> +<link href="../site_libs/quarto-html/tippy.css" rel="stylesheet"> +<link href="../site_libs/quarto-html/quarto-syntax-highlighting.css" rel="stylesheet" id="quarto-text-highlighting-styles"> +<script src="../site_libs/bootstrap/bootstrap.min.js"></script> +<link href="../site_libs/bootstrap/bootstrap-icons.css" rel="stylesheet"> +<link href="../site_libs/bootstrap/bootstrap.min.css" rel="stylesheet" id="quarto-bootstrap" data-mode="light"> +<script id="quarto-search-options" type="application/json">{ + "location": "navbar", + "copy-button": false, + "collapse-after": 3, + "panel-placement": "end", + "type": "overlay", + "limit": 20, + "language": { + "search-no-results-text": "No results", + "search-matching-documents-text": "matching documents", + "search-copy-link-title": "Copy link to search", + "search-hide-matches-text": "Hide additional matches", + "search-more-match-text": "more match in this document", + "search-more-matches-text": "more matches in this document", + "search-clear-button-title": "Clear", + "search-detached-cancel-button-title": "Cancel", + "search-submit-button-title": "Submit", + "search-label": "Search" + } +}</script> +<script async="" src="https://www.googletagmanager.com/gtag/js?id=G-NXJNCVR18L"></script> + +<script type="text/javascript"> + +window.dataLayer = window.dataLayer || []; +function gtag(){dataLayer.push(arguments);} +gtag('js', new Date()); +gtag('config', 'G-NXJNCVR18L', { 'anonymize_ip': true}); +</script> + + +<link rel="stylesheet" href="../styles.css"> +<meta property="og:title" content="hierarchicalforecast - Install"> +<meta property="og:description" content="Install HierachicalForecast with pip or conda"> +<meta property="og:site-name" content="hierarchicalforecast"> +<meta name="twitter:title" content="hierarchicalforecast - Install"> +<meta name="twitter:description" content="Install HierachicalForecast with pip or conda"> +<meta name="twitter:card" content="summary"> +</head> + +<body class="nav-sidebar floating nav-fixed"> + +<div id="quarto-search-results"></div> + <header id="quarto-header" class="headroom fixed-top"> + <nav class="navbar navbar-expand-lg navbar-dark "> + <div class="navbar-container container-fluid"> + <div class="navbar-brand-container"> + <a class="navbar-brand" href="../index.html"> + <span class="navbar-title">hierarchicalforecast</span> + </a> + </div> + <div id="quarto-search" class="" title="Search"></div> + <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + <span class="navbar-toggler-icon"></span> +</button> + <div class="collapse navbar-collapse" id="navbarCollapse"> + <ul class="navbar-nav navbar-nav-scroll me-auto"> + <li class="nav-item"> + <a class="nav-link active" href="../examples/tourismsmall.html" rel="" target="" aria-current="page"> + <span class="menu-text">Get Started</span></a> + </li> + <li class="nav-item dropdown "> + <a class="nav-link dropdown-toggle" href="#" id="nav-menu-nixtlaverse" role="button" data-bs-toggle="dropdown" aria-expanded="false" rel="" target=""> + <span class="menu-text">NixtlaVerse</span> + </a> + <ul class="dropdown-menu" aria-labelledby="nav-menu-nixtlaverse"> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/mlforecast" rel="" target=""> + <span class="dropdown-text">MLForecast š¤</span></a> + </li> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/neuralforecast" rel="" target=""> + <span class="dropdown-text">NeuralForecast š§ </span></a> + </li> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/statsforecast" rel="" target=""> + <span class="dropdown-text">StatsForecast ā”ļø</span></a> + </li> + </ul> + </li> + <li class="nav-item dropdown "> + <a class="nav-link dropdown-toggle" href="#" id="nav-menu-help" role="button" data-bs-toggle="dropdown" aria-expanded="false" rel="" target=""> + <span class="menu-text">Help</span> + </a> + <ul class="dropdown-menu" aria-labelledby="nav-menu-help"> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/hierarchicalforecast/issues/new/choose" rel="" target=""><i class="bi bi-bug" role="img"> +</i> + <span class="dropdown-text">Report an Issue</span></a> + </li> + <li> + <a class="dropdown-item" href="https://join.slack.com/t/nixtlacommunity/shared_invite/zt-1kd5m5db7-7OOfy0xVNf1PcvCiAPWvPw" rel="" target=""><i class="bi bi-chat-right-text" role="img"> +</i> + <span class="dropdown-text">Join our Slack</span></a> + </li> + </ul> + </li> +</ul> + <ul class="navbar-nav navbar-nav-scroll ms-auto"> + <li class="nav-item compact"> + <a class="nav-link" href="https://github.com/nixtla/hierarchicalforecast" rel="" target=""><i class="bi bi-github" role="img"> +</i> + <span class="menu-text"></span></a> + </li> + <li class="nav-item compact"> + <a class="nav-link" href="https://twitter.com/nixtlainc" rel="" target=""><i class="bi bi-twitter" role="img" aria-label="Nixtla Twitter"> +</i> + <span class="menu-text"></span></a> + </li> +</ul> + <div class="quarto-navbar-tools"> +</div> + </div> <!-- /navcollapse --> + </div> <!-- /container-fluid --> + </nav> + <nav class="quarto-secondary-nav"> + <div class="container-fluid d-flex"> + <button type="button" class="quarto-btn-toggle btn" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + <i class="bi bi-layout-text-sidebar-reverse"></i> + </button> + <nav class="quarto-page-breadcrumbs" aria-label="breadcrumb"><ol class="breadcrumb"><li class="breadcrumb-item"><a href="../examples/installation.html">Getting Started</a></li><li class="breadcrumb-item"><a href="../examples/installation.html">Install</a></li></ol></nav> + <a class="flex-grow-1" role="button" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + </a> + </div> + </nav> +</header> +<!-- content --> +<div id="quarto-content" class="quarto-container page-columns page-rows-contents page-layout-article page-navbar"> +<!-- sidebar --> + <nav id="quarto-sidebar" class="sidebar collapse collapse-horizontal sidebar-navigation floating overflow-auto"> + <div class="sidebar-menu-container"> + <ul class="list-unstyled mt-1"> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../index.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Hierarchical Forecast š</span></a> + </div> +</li> + <li class="px-0"><hr class="sidebar-divider hi "></li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-1" aria-expanded="true"> + <span class="menu-text">Getting Started</span></a> + <a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-1" aria-expanded="true" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-1" class="collapse list-unstyled sidebar-section depth1 show"> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/installation.html" class="sidebar-item-text sidebar-link active"> + <span class="menu-text">Install</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/tourismsmall.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Reconciliation Quick Start</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/introduction.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Introduction</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-2" aria-expanded="false"> + <span class="menu-text">Tutorials</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-2" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-2" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-3" aria-expanded="false"> + <span class="menu-text">Point Reconciliation</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-3" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-3" class="collapse list-unstyled sidebar-section depth2 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Geographical Aggregation (Tourism)</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australianprisonpopulation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Geographical Aggregation (Prison Population)</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/nonnegativereconciliation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Non-Negative MinTrace</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-4" aria-expanded="false"> + <span class="menu-text">Probabilistic Reconciliation</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-4" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-4" class="collapse list-unstyled sidebar-section depth2 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Normality</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism-bootstraped-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Bootstrap</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism-permbu-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">PERMBU</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/tourismlarge-evaluation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Probabilistic Forecast Evaluation</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-5" aria-expanded="false"> + <span class="menu-text">ML Forecast Reconciliation</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-5" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-5" class="collapse list-unstyled sidebar-section depth2 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/hierarchicalforecast-gluonts.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">GluonTS</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/mlframeworksexample.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Neural/MLForecast</span></a> + </div> +</li> + </ul> + </li> + </ul> + </li> + <li class="sidebar-item"> + <span class="menu-text">Methods</span> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-6" aria-expanded="false"> + <span class="menu-text">API Reference</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-6" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-6" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../core.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Core </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../methods.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Reconciliation Methods </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../probabilistic_methods.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Probabilistic Methods </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../evaluation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Hierarchical Evaluation</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../utils.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Aggregation/Visualization Utils</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-7" aria-expanded="false"> + <span class="menu-text">Community</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-7" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-7" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item"> + <span class="menu-text">Contributing</span> + </li> + </ul> + </li> + </ul> + </div> +</nav> +<div id="quarto-sidebar-glass" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass"></div> +<!-- margin-sidebar --> + <div id="quarto-margin-sidebar" class="sidebar margin-sidebar"> + + </div> +<!-- main --> +<main class="content" id="quarto-document-content"> + +<header id="title-block-header" class="quarto-title-block default"> +<div class="quarto-title"> +<h1 class="title">Install</h1> +</div> + +<div> + <div class="description"> + Install HierachicalForecast with pip or conda + </div> +</div> + + +<div class="quarto-title-meta"> + + + + + </div> + + +</header> + +<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! --> +<p>You can install the <em>released version</em> of <code>HierachicalForecast</code> from the <a href="https://pypi.org">Python package index</a> with:</p> +<div class="sourceCode" id="cb1"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a>pip install hierarchicalforecast</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<p>or</p> +<div class="sourceCode" id="cb2"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a>conda install <span class="op">-</span>c conda<span class="op">-</span>forge hierarchicalforecast</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="callout callout-style-default callout-tip callout-titled"> +<div class="callout-header d-flex align-content-center"> +<div class="callout-icon-container"> +<i class="callout-icon"></i> +</div> +<div class="callout-title-container flex-fill"> +Tip +</div> +</div> +<div class="callout-body-container callout-body"> +<p>We recommend installing your libraries inside a python virtual or <a href="https://docs.conda.io/projects/conda/en/latest/user-guide/install/macos.html">conda environment</a>.</p> +</div> +</div> +<section id="user-our-env-optional" class="level4"> +<h4 class="anchored" data-anchor-id="user-our-env-optional">User our env (optional)</h4> +<p>If you donāt have a Conda environment and need tools like Numba, Pandas, NumPy, Jupyter, StatsModels, and Nbdev you can use ours by following these steps:</p> +<ol type="1"> +<li>Clone the HierachicalForecast repo:</li> +</ol> +<div class="sourceCode" id="cb3"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> git clone https://github.com/Nixtla/hierachicalforecast.git <span class="kw">&&</span> <span class="bu">cd</span> hierachicalforecast</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<ol start="2" type="1"> +<li>Create the environment using the <code>environment.yml</code> file:</li> +</ol> +<div class="sourceCode" id="cb4"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> conda env create <span class="at">-f</span> environment.yml</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<ol start="3" type="1"> +<li>Activate the environment:</li> +</ol> +<div class="sourceCode" id="cb5"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="ex">$</span> conda activate statsforecast</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> + + +</section> + +<p>If you find the code useful, please ā us on <a href="https://github.com/nixtla/hierarchicalforecast">Github</a></p></main> <!-- /main --> +<script id="quarto-html-after-body" type="application/javascript"> +window.document.addEventListener("DOMContentLoaded", function (event) { + const toggleBodyColorMode = (bsSheetEl) => { + const mode = bsSheetEl.getAttribute("data-mode"); + const bodyEl = window.document.querySelector("body"); + if (mode === "dark") { + bodyEl.classList.add("quarto-dark"); + bodyEl.classList.remove("quarto-light"); + } else { + bodyEl.classList.add("quarto-light"); + bodyEl.classList.remove("quarto-dark"); + } + } + const toggleBodyColorPrimary = () => { + const bsSheetEl = window.document.querySelector("link#quarto-bootstrap"); + if (bsSheetEl) { + toggleBodyColorMode(bsSheetEl); + } + } + toggleBodyColorPrimary(); + const icon = "ī§"; + const anchorJS = new window.AnchorJS(); + anchorJS.options = { + placement: 'right', + icon: icon + }; + anchorJS.add('.anchored'); + const isCodeAnnotation = (el) => { + for (const clz of el.classList) { + if (clz.startsWith('code-annotation-')) { + return true; + } + } + return false; + } + const clipboard = new window.ClipboardJS('.code-copy-button', { + text: function(trigger) { + const codeEl = trigger.previousElementSibling.cloneNode(true); + for (const childEl of codeEl.children) { + if (isCodeAnnotation(childEl)) { + childEl.remove(); + } + } + return codeEl.innerText; + } + }); + clipboard.on('success', function(e) { + // button target + const button = e.trigger; + // don't keep focus + button.blur(); + // flash "checked" + button.classList.add('code-copy-button-checked'); + var currentTitle = button.getAttribute("title"); + button.setAttribute("title", "Copied!"); + let tooltip; + if (window.bootstrap) { + button.setAttribute("data-bs-toggle", "tooltip"); + button.setAttribute("data-bs-placement", "left"); + button.setAttribute("data-bs-title", "Copied!"); + tooltip = new bootstrap.Tooltip(button, + { trigger: "manual", + customClass: "code-copy-button-tooltip", + offset: [0, -8]}); + tooltip.show(); + } + setTimeout(function() { + if (tooltip) { + tooltip.hide(); + button.removeAttribute("data-bs-title"); + button.removeAttribute("data-bs-toggle"); + button.removeAttribute("data-bs-placement"); + } + button.setAttribute("title", currentTitle); + button.classList.remove('code-copy-button-checked'); + }, 1000); + // clear code selection + e.clearSelection(); + }); + function tippyHover(el, contentFn) { + const config = { + allowHTML: true, + content: contentFn, + maxWidth: 500, + delay: 100, + arrow: false, + appendTo: function(el) { + return el.parentElement; + }, + interactive: true, + interactiveBorder: 10, + theme: 'quarto', + placement: 'bottom-start' + }; + window.tippy(el, config); + } + const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]'); + for (var i=0; i<noterefs.length; i++) { + const ref = noterefs[i]; + tippyHover(ref, function() { + // use id or data attribute instead here + let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href'); + try { href = new URL(href).hash; } catch {} + const id = href.replace(/^#\/?/, ""); + const note = window.document.getElementById(id); + return note.innerHTML; + }); + } + let selectedAnnoteEl; + const selectorForAnnotation = ( cell, annotation) => { + let cellAttr = 'data-code-cell="' + cell + '"'; + let lineAttr = 'data-code-annotation="' + annotation + '"'; + const selector = 'span[' + cellAttr + '][' + lineAttr + ']'; + return selector; + } + const selectCodeLines = (annoteEl) => { + const doc = window.document; + const targetCell = annoteEl.getAttribute("data-target-cell"); + const targetAnnotation = annoteEl.getAttribute("data-target-annotation"); + const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation)); + const lines = annoteSpan.getAttribute("data-code-lines").split(","); + const lineIds = lines.map((line) => { + return targetCell + "-" + line; + }) + let top = null; + let height = null; + let parent = null; + if (lineIds.length > 0) { + //compute the position of the single el (top and bottom and make a div) + const el = window.document.getElementById(lineIds[0]); + top = el.offsetTop; + height = el.offsetHeight; + parent = el.parentElement.parentElement; + if (lineIds.length > 1) { + const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]); + const bottom = lastEl.offsetTop + lastEl.offsetHeight; + height = bottom - top; + } + if (top !== null && height !== null && parent !== null) { + // cook up a div (if necessary) and position it + let div = window.document.getElementById("code-annotation-line-highlight"); + if (div === null) { + div = window.document.createElement("div"); + div.setAttribute("id", "code-annotation-line-highlight"); + div.style.position = 'absolute'; + parent.appendChild(div); + } + div.style.top = top - 2 + "px"; + div.style.height = height + 4 + "px"; + let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter"); + if (gutterDiv === null) { + gutterDiv = window.document.createElement("div"); + gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter"); + gutterDiv.style.position = 'absolute'; + const codeCell = window.document.getElementById(targetCell); + const gutter = codeCell.querySelector('.code-annotation-gutter'); + gutter.appendChild(gutterDiv); + } + gutterDiv.style.top = top - 2 + "px"; + gutterDiv.style.height = height + 4 + "px"; + } + selectedAnnoteEl = annoteEl; + } + }; + const unselectCodeLines = () => { + const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"]; + elementsIds.forEach((elId) => { + const div = window.document.getElementById(elId); + if (div) { + div.remove(); + } + }); + selectedAnnoteEl = undefined; + }; + // Attach click handler to the DT + const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); + for (const annoteDlNode of annoteDls) { + annoteDlNode.addEventListener('click', (event) => { + const clickedEl = event.target; + if (clickedEl !== selectedAnnoteEl) { + unselectCodeLines(); + const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active'); + if (activeEl) { + activeEl.classList.remove('code-annotation-active'); + } + selectCodeLines(clickedEl); + clickedEl.classList.add('code-annotation-active'); + } else { + // Unselect the line + unselectCodeLines(); + clickedEl.classList.remove('code-annotation-active'); + } + }); + } + const findCites = (el) => { + const parentEl = el.parentElement; + if (parentEl) { + const cites = parentEl.dataset.cites; + if (cites) { + return { + el, + cites: cites.split(' ') + }; + } else { + return findCites(el.parentElement) + } + } else { + return undefined; + } + }; + var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]'); + for (var i=0; i<bibliorefs.length; i++) { + const ref = bibliorefs[i]; + const citeInfo = findCites(ref); + if (citeInfo) { + tippyHover(citeInfo.el, function() { + var popup = window.document.createElement('div'); + citeInfo.cites.forEach(function(cite) { + var citeDiv = window.document.createElement('div'); + citeDiv.classList.add('hanging-indent'); + citeDiv.classList.add('csl-entry'); + var biblioDiv = window.document.getElementById('ref-' + cite); + if (biblioDiv) { + citeDiv.innerHTML = biblioDiv.innerHTML; + } + popup.appendChild(citeDiv); + }); + return popup.innerHTML; + }); + } + } +}); +</script> +</div> <!-- /content --> + + + +<footer class="footer"><div class="nav-footer"><div class="nav-footer-center"><div class="toc-actions"><div><i class="bi bi-github"></i></div><div class="action-links"><p><a href="https://github.com/Nixtla/hierarchicalforecast/issues/new" class="toc-action">Report an issue</a></p></div></div></div></div></footer></body></html> \ No newline at end of file diff --git a/examples/introduction.html b/examples/introduction.html new file mode 100644 index 00000000..eaa7f6c5 --- /dev/null +++ b/examples/introduction.html @@ -0,0 +1,1248 @@ +<!DOCTYPE html> +<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head> + +<meta charset="utf-8"> +<meta name="generator" content="quarto-1.3.450"> + +<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes"> + +<meta name="description" content="Introduction to Hierarchial Forecasting using HierarchialForecast"> + +<title>hierarchicalforecast - Introduction</title> +<style> +code{white-space: pre-wrap;} +span.smallcaps{font-variant: small-caps;} +div.columns{display: flex; gap: min(4vw, 1.5em);} +div.column{flex: auto; overflow-x: auto;} +div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;} +ul.task-list{list-style: none;} +ul.task-list li input[type="checkbox"] { + width: 0.8em; + margin: 0 0.8em 0.2em -1em; /* quarto-specific, see https://github.com/quarto-dev/quarto-cli/issues/4556 */ + vertical-align: middle; +} +/* CSS for syntax highlighting */ +pre > code.sourceCode { white-space: pre; position: relative; } +pre > code.sourceCode > span { display: inline-block; line-height: 1.25; } +pre > code.sourceCode > span:empty { height: 1.2em; } +.sourceCode { overflow: visible; } +code.sourceCode > span { color: inherit; text-decoration: inherit; } +div.sourceCode { margin: 1em 0; } +pre.sourceCode { margin: 0; } +@media screen { +div.sourceCode { overflow: auto; } +} +@media print { +pre > code.sourceCode { white-space: pre-wrap; } +pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; } +} +pre.numberSource code + { counter-reset: source-line 0; } +pre.numberSource code > span + { position: relative; left: -4em; counter-increment: source-line; } +pre.numberSource code > span > a:first-child::before + { content: counter(source-line); + position: relative; left: -1em; text-align: right; vertical-align: baseline; + border: none; display: inline-block; + -webkit-touch-callout: none; -webkit-user-select: none; + -khtml-user-select: none; -moz-user-select: none; + -ms-user-select: none; user-select: none; + padding: 0 4px; width: 4em; + } +pre.numberSource { margin-left: 3em; padding-left: 4px; } +div.sourceCode + { } +@media screen { +pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; } +} +</style> + + +<script src="../site_libs/quarto-nav/quarto-nav.js"></script> +<script src="../site_libs/quarto-nav/headroom.min.js"></script> +<script src="../site_libs/clipboard/clipboard.min.js"></script> +<script src="../site_libs/quarto-search/autocomplete.umd.js"></script> +<script src="../site_libs/quarto-search/fuse.min.js"></script> +<script src="../site_libs/quarto-search/quarto-search.js"></script> +<meta name="quarto:offset" content="../"> +<link href="../favicon_png.png" rel="icon" type="image/png"> +<script src="../site_libs/quarto-html/quarto.js"></script> +<script src="../site_libs/quarto-html/popper.min.js"></script> +<script src="../site_libs/quarto-html/tippy.umd.min.js"></script> +<script src="../site_libs/quarto-html/anchor.min.js"></script> +<link href="../site_libs/quarto-html/tippy.css" rel="stylesheet"> +<link href="../site_libs/quarto-html/quarto-syntax-highlighting.css" rel="stylesheet" id="quarto-text-highlighting-styles"> +<script src="../site_libs/bootstrap/bootstrap.min.js"></script> +<link href="../site_libs/bootstrap/bootstrap-icons.css" rel="stylesheet"> +<link href="../site_libs/bootstrap/bootstrap.min.css" rel="stylesheet" id="quarto-bootstrap" data-mode="light"> +<script id="quarto-search-options" type="application/json">{ + "location": "navbar", + "copy-button": false, + "collapse-after": 3, + "panel-placement": "end", + "type": "overlay", + "limit": 20, + "language": { + "search-no-results-text": "No results", + "search-matching-documents-text": "matching documents", + "search-copy-link-title": "Copy link to search", + "search-hide-matches-text": "Hide additional matches", + "search-more-match-text": "more match in this document", + "search-more-matches-text": "more matches in this document", + "search-clear-button-title": "Clear", + "search-detached-cancel-button-title": "Cancel", + "search-submit-button-title": "Submit", + "search-label": "Search" + } +}</script> +<script async="" src="https://www.googletagmanager.com/gtag/js?id=G-NXJNCVR18L"></script> + +<script type="text/javascript"> + +window.dataLayer = window.dataLayer || []; +function gtag(){dataLayer.push(arguments);} +gtag('js', new Date()); +gtag('config', 'G-NXJNCVR18L', { 'anonymize_ip': true}); +</script> +<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js" integrity="sha512-c3Nl8+7g4LMSTdrm621y7kf9v3SDPnhxLNhcjFJbKECVnmZHTdo+IRO05sNLTH/D3vA6u1X32ehoLC7WFVdheg==" crossorigin="anonymous"></script> +<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js" integrity="sha512-bLT0Qm9VnAYZDflyKcBaQ2gg0hSYNQrJ8RilYldYQ1FxQYoCLtUjuuRuZo+fjqhx/qtq/1itJ0C2ejDxltZVFg==" crossorigin="anonymous"></script> +<script type="application/javascript">define('jquery', [],function() {return window.jQuery;})</script> + + <script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script> + <script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml-full.js" type="text/javascript"></script> + +<link rel="stylesheet" href="../styles.css"> +<meta property="og:title" content="hierarchicalforecast - Introduction"> +<meta property="og:description" content="Introduction to Hierarchial Forecasting using HierarchialForecast"> +<meta property="og:image" content="https://colab.research.google.com/assets/colab-badge.svg"> +<meta property="og:site-name" content="hierarchicalforecast"> +<meta name="twitter:title" content="hierarchicalforecast - Introduction"> +<meta name="twitter:description" content="Introduction to Hierarchial Forecasting using HierarchialForecast"> +<meta name="twitter:image" content="https://colab.research.google.com/assets/colab-badge.svg"> +<meta name="twitter:card" content="summary_large_image"> +</head> + +<body class="nav-sidebar floating nav-fixed"> + +<div id="quarto-search-results"></div> + <header id="quarto-header" class="headroom fixed-top"> + <nav class="navbar navbar-expand-lg navbar-dark "> + <div class="navbar-container container-fluid"> + <div class="navbar-brand-container"> + <a class="navbar-brand" href="../index.html"> + <span class="navbar-title">hierarchicalforecast</span> + </a> + </div> + <div id="quarto-search" class="" title="Search"></div> + <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + <span class="navbar-toggler-icon"></span> +</button> + <div class="collapse navbar-collapse" id="navbarCollapse"> + <ul class="navbar-nav navbar-nav-scroll me-auto"> + <li class="nav-item"> + <a class="nav-link active" href="../examples/tourismsmall.html" rel="" target="" aria-current="page"> + <span class="menu-text">Get Started</span></a> + </li> + <li class="nav-item dropdown "> + <a class="nav-link dropdown-toggle" href="#" id="nav-menu-nixtlaverse" role="button" data-bs-toggle="dropdown" aria-expanded="false" rel="" target=""> + <span class="menu-text">NixtlaVerse</span> + </a> + <ul class="dropdown-menu" aria-labelledby="nav-menu-nixtlaverse"> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/mlforecast" rel="" target=""> + <span class="dropdown-text">MLForecast š¤</span></a> + </li> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/neuralforecast" rel="" target=""> + <span class="dropdown-text">NeuralForecast š§ </span></a> + </li> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/statsforecast" rel="" target=""> + <span class="dropdown-text">StatsForecast ā”ļø</span></a> + </li> + </ul> + </li> + <li class="nav-item dropdown "> + <a class="nav-link dropdown-toggle" href="#" id="nav-menu-help" role="button" data-bs-toggle="dropdown" aria-expanded="false" rel="" target=""> + <span class="menu-text">Help</span> + </a> + <ul class="dropdown-menu" aria-labelledby="nav-menu-help"> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/hierarchicalforecast/issues/new/choose" rel="" target=""><i class="bi bi-bug" role="img"> +</i> + <span class="dropdown-text">Report an Issue</span></a> + </li> + <li> + <a class="dropdown-item" href="https://join.slack.com/t/nixtlacommunity/shared_invite/zt-1kd5m5db7-7OOfy0xVNf1PcvCiAPWvPw" rel="" target=""><i class="bi bi-chat-right-text" role="img"> +</i> + <span class="dropdown-text">Join our Slack</span></a> + </li> + </ul> + </li> +</ul> + <ul class="navbar-nav navbar-nav-scroll ms-auto"> + <li class="nav-item compact"> + <a class="nav-link" href="https://github.com/nixtla/hierarchicalforecast" rel="" target=""><i class="bi bi-github" role="img"> +</i> + <span class="menu-text"></span></a> + </li> + <li class="nav-item compact"> + <a class="nav-link" href="https://twitter.com/nixtlainc" rel="" target=""><i class="bi bi-twitter" role="img" aria-label="Nixtla Twitter"> +</i> + <span class="menu-text"></span></a> + </li> +</ul> + <div class="quarto-navbar-tools"> +</div> + </div> <!-- /navcollapse --> + </div> <!-- /container-fluid --> + </nav> + <nav class="quarto-secondary-nav"> + <div class="container-fluid d-flex"> + <button type="button" class="quarto-btn-toggle btn" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + <i class="bi bi-layout-text-sidebar-reverse"></i> + </button> + <nav class="quarto-page-breadcrumbs" aria-label="breadcrumb"><ol class="breadcrumb"><li class="breadcrumb-item"><a href="../examples/installation.html">Getting Started</a></li><li class="breadcrumb-item"><a href="../examples/introduction.html">Introduction</a></li></ol></nav> + <a class="flex-grow-1" role="button" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + </a> + </div> + </nav> +</header> +<!-- content --> +<div id="quarto-content" class="quarto-container page-columns page-rows-contents page-layout-article page-navbar"> +<!-- sidebar --> + <nav id="quarto-sidebar" class="sidebar collapse collapse-horizontal sidebar-navigation floating overflow-auto"> + <div class="sidebar-menu-container"> + <ul class="list-unstyled mt-1"> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../index.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Hierarchical Forecast š</span></a> + </div> +</li> + <li class="px-0"><hr class="sidebar-divider hi "></li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-1" aria-expanded="true"> + <span class="menu-text">Getting Started</span></a> + <a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-1" aria-expanded="true" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-1" class="collapse list-unstyled sidebar-section depth1 show"> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/installation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Install</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/tourismsmall.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Reconciliation Quick Start</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/introduction.html" class="sidebar-item-text sidebar-link active"> + <span class="menu-text">Introduction</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-2" aria-expanded="false"> + <span class="menu-text">Tutorials</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-2" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-2" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-3" aria-expanded="false"> + <span class="menu-text">Point Reconciliation</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-3" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-3" class="collapse list-unstyled sidebar-section depth2 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Geographical Aggregation (Tourism)</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australianprisonpopulation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Geographical Aggregation (Prison Population)</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/nonnegativereconciliation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Non-Negative MinTrace</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-4" aria-expanded="false"> + <span class="menu-text">Probabilistic Reconciliation</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-4" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-4" class="collapse list-unstyled sidebar-section depth2 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Normality</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism-bootstraped-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Bootstrap</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism-permbu-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">PERMBU</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/tourismlarge-evaluation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Probabilistic Forecast Evaluation</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-5" aria-expanded="false"> + <span class="menu-text">ML Forecast Reconciliation</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-5" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-5" class="collapse list-unstyled sidebar-section depth2 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/hierarchicalforecast-gluonts.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">GluonTS</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/mlframeworksexample.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Neural/MLForecast</span></a> + </div> +</li> + </ul> + </li> + </ul> + </li> + <li class="sidebar-item"> + <span class="menu-text">Methods</span> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-6" aria-expanded="false"> + <span class="menu-text">API Reference</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-6" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-6" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../core.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Core </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../methods.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Reconciliation Methods </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../probabilistic_methods.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Probabilistic Methods </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../evaluation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Hierarchical Evaluation</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../utils.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Aggregation/Visualization Utils</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-7" aria-expanded="false"> + <span class="menu-text">Community</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-7" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-7" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item"> + <span class="menu-text">Contributing</span> + </li> + </ul> + </li> + </ul> + </div> +</nav> +<div id="quarto-sidebar-glass" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass"></div> +<!-- margin-sidebar --> + <div id="quarto-margin-sidebar" class="sidebar margin-sidebar"> + <nav id="TOC" role="doc-toc" class="toc-active"> + <h2 id="toc-title">On this page</h2> + + <ul> + <li><a href="#hierarchical-series" id="toc-hierarchical-series" class="nav-link active" data-scroll-target="#hierarchical-series">1. Hierarchical Series</a></li> + <li><a href="#hierarchical-forecast" id="toc-hierarchical-forecast" class="nav-link" data-scroll-target="#hierarchical-forecast">2. Hierarchical Forecast</a></li> + <li><a href="#minimal-example" id="toc-minimal-example" class="nav-link" data-scroll-target="#minimal-example">3. Minimal Example</a> + <ul class="collapse"> + <li><a href="#wrangling-data" id="toc-wrangling-data" class="nav-link" data-scroll-target="#wrangling-data">Wrangling Data</a></li> + <li><a href="#base-predictions" id="toc-base-predictions" class="nav-link" data-scroll-target="#base-predictions">Base Predictions</a></li> + <li><a href="#reconciliation" id="toc-reconciliation" class="nav-link" data-scroll-target="#reconciliation">Reconciliation</a></li> + </ul></li> + <li><a href="#references" id="toc-references" class="nav-link" data-scroll-target="#references">References</a></li> + </ul> +<div class="toc-actions"><div><i class="bi bi-github"></i></div><div class="action-links"><p><a href="https://github.com/Nixtla/hierarchicalforecast/issues/new" class="toc-action">Report an issue</a></p></div></div></nav> + </div> +<!-- main --> +<main class="content" id="quarto-document-content"> + +<header id="title-block-header" class="quarto-title-block default"> +<div class="quarto-title"> +<h1 class="title">Introduction</h1> +</div> + +<div> + <div class="description"> + Introduction to Hierarchial Forecasting using <code>HierarchialForecast</code> + </div> +</div> + + +<div class="quarto-title-meta"> + + + + + </div> + + +</header> + +<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! --> +<p>You can run these experiments using CPU or GPU with Google Colab.</p> +<p><a href="https://colab.research.google.com/github/Nixtla/hierarchicalforecast/blob/main/nbs/examples/Introduction.ipynb" target="_parent"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"></a></p> +<section id="hierarchical-series" class="level2"> +<h2 class="anchored" data-anchor-id="hierarchical-series">1. Hierarchical Series</h2> +<p>In many applications, a set of time series is hierarchically organized. Examples include the presence of geographic levels, products, or categories that define different types of aggregations.</p> +<p>In such scenarios, forecasters are often required to provide predictions for all disaggregate and aggregate series. A natural desire is for those predictions to be <strong>ācoherentā</strong>, that is, for the bottom series to add up precisely to the forecasts of the aggregated series.</p> +<div class="quarto-figure quarto-figure-center"> +<figure class="figure"> +<p><img src="./imgs/hierarchical_motivation1.png" class="img-fluid figure-img"></p> +<figcaption class="figure-caption">Figure 1. A two level time series hierarchical structure, with four bottom level variables.</figcaption> +</figure> +</div> +<p>Figure 1. shows a simple hierarchical structure where we have four bottom-level series, two middle-level series, and the top level representing the total aggregation. Its hierarchical aggregations or coherency constraints are:</p> +<p><span class="math display">\[\begin{align} + y_{\mathrm{Total},\tau} = y_{\beta_{1},\tau}+y_{\beta_{2},\tau}+y_{\beta_{3},\tau}+y_{\beta_{4},\tau} + \qquad \qquad \qquad \qquad \qquad \\ + \mathbf{y}_{[a],\tau}=\left[y_{\mathrm{Total},\tau},\; y_{\beta_{1},\tau}+y_{\beta_{2},\tau},\;y_{\beta_{3},\tau}+y_{\beta_{4},\tau}\right]^{\intercal} + \qquad + \mathbf{y}_{[b],\tau}=\left[ y_{\beta_{1},\tau},\; y_{\beta_{2},\tau},\; y_{\beta_{3},\tau},\; y_{\beta_{4},\tau} \right]^{\intercal} +\end{align}\]</span></p> +<p>Luckily these constraints can be compactly expressed with the following matrices:</p> +<p><span class="math display">\[\begin{align} +\mathbf{S}_{[a,b][b]} += +\begin{bmatrix} +\mathbf{A}_{\mathrm{[a][b]}} \\ + \\ + \\ +\mathbf{I}_{\mathrm{[b][b]}} \\ + \\ +\end{bmatrix} += +\begin{bmatrix} +1 & 1 & 1 & 1 \\ +1 & 1 & 0 & 0 \\ +0 & 0 & 1 & 1 \\ +1 & 0 & 0 & 0 \\ +0 & 1 & 0 & 0 \\ +0 & 0 & 1 & 0 \\ +0 & 0 & 0 & 1 \\ +\end{bmatrix} +\end{align}\]</span></p> +<p>where <span class="math inline">\(\mathbf{A}_{[a,b][b]}\)</span> aggregates the bottom series to the upper levels, and <span class="math inline">\(\mathbf{I}_{\mathrm{[b][b]}}\)</span> is an identity matrix. The representation of the hierarchical series is then:</p> +<p><span class="math display">\[\begin{align} +\mathbf{y}_{[a,b],\tau} = \mathbf{S}_{[a,b][b]} \mathbf{y}_{[b],\tau} +\end{align}\]</span></p> +<p>To visualize an example, in Figure 2. One can think of the hierarchical time series structure levels to represent different geographical aggregations. For example, in Figure 2. the top level is the total aggregation of series within a country, the middle level being its states and the bottom level its regions.</p> +<div class="quarto-figure quarto-figure-center"> +<figure class="figure"> +<p><img src="./imgs/hierarchical_motivation2.png" class="img-fluid figure-img"></p> +<figcaption class="figure-caption">Figure 2. A hierarchy can be composed of geographic levels. In this example the top level corresponds to country aggregation, middle level to states, and bottom level to regions.</figcaption> +</figure> +</div> +</section> +<section id="hierarchical-forecast" class="level2"> +<h2 class="anchored" data-anchor-id="hierarchical-forecast">2. Hierarchical Forecast</h2> +<p>To achieve <strong>ācoherencyā</strong>, most statistical solutions to the hierarchical forecasting challenge implement a two-stage reconciliation process.<br> +1. First, we obtain a set of the base forecast <span class="math inline">\(\mathbf{\hat{y}}_{[a,b],\tau}\)</span> 2. Later, we reconcile them into coherent forecasts <span class="math inline">\(\mathbf{\tilde{y}}_{[a,b],\tau}\)</span>.</p> +<p>Most hierarchical reconciliation methods can be expressed by the following transformations:</p> +<p><span class="math display">\[\begin{align} +\tilde{\mathbf{y}}_{[a,b],\tau} = \mathbf{S}_{[a,b][b]} \mathbf{P}_{[b][a,b]} \hat{\mathbf{y}}_{[a,b],\tau} +\end{align}\]</span></p> +<p>The HierarchicalForecast library offers a Python collection of reconciliation methods, datasets, evaluation and visualization tools for the task. Among its available reconciliation methods we have <a href="https://Nixtla.github.io/hierarchicalforecast/methods.html#bottomup"><code>BottomUp</code></a>, <a href="https://Nixtla.github.io/hierarchicalforecast/methods.html#topdown"><code>TopDown</code></a>, <a href="https://Nixtla.github.io/hierarchicalforecast/methods.html#middleout"><code>MiddleOut</code></a>, <a href="https://Nixtla.github.io/hierarchicalforecast/methods.html#mintrace"><code>MinTrace</code></a>, <a href="https://Nixtla.github.io/hierarchicalforecast/methods.html#erm"><code>ERM</code></a>. Among its probabilistic coherent methods we have <a href="https://Nixtla.github.io/hierarchicalforecast/probabilistic_methods.html#normality"><code>Normality</code></a>, <a href="https://Nixtla.github.io/hierarchicalforecast/probabilistic_methods.html#bootstrap"><code>Bootstrap</code></a>, <a href="https://Nixtla.github.io/hierarchicalforecast/probabilistic_methods.html#permbu"><code>PERMBU</code></a>.</p> +</section> +<section id="minimal-example" class="level2"> +<h2 class="anchored" data-anchor-id="minimal-example">3. Minimal Example</h2> +<div class="cell"> +<div class="sourceCode cell-code" id="cb1"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="op">!</span>pip install hierarchicalforecast</span> +<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="op">!</span>pip install <span class="op">-</span>U numba statsforecast datasetsforecast</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<section id="wrangling-data" class="level3"> +<h3 class="anchored" data-anchor-id="wrangling-data">Wrangling Data</h3> +<div class="cell"> +<div class="sourceCode cell-code" id="cb2"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> numpy <span class="im">as</span> np</span> +<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> pandas <span class="im">as</span> pd</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<p>We are going to creat a synthetic data set to illustrate a hierarchical time series structure like the one in Figure 1.</p> +<p>We will create a two level structure with four bottom series where aggregations of the series are self evident.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb3"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="co"># Create Figure 1. synthetic bottom data</span></span> +<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>ds <span class="op">=</span> pd.date_range(start<span class="op">=</span><span class="st">'2000-01-01'</span>, end<span class="op">=</span><span class="st">'2000-08-01'</span>, freq<span class="op">=</span><span class="st">'MS'</span>)</span> +<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a>y_base <span class="op">=</span> np.arange(<span class="dv">1</span>,<span class="dv">9</span>)</span> +<span id="cb3-4"><a href="#cb3-4" aria-hidden="true" tabindex="-1"></a>r1 <span class="op">=</span> y_base <span class="op">*</span> (<span class="dv">10</span><span class="op">**</span><span class="dv">1</span>)</span> +<span id="cb3-5"><a href="#cb3-5" aria-hidden="true" tabindex="-1"></a>r2 <span class="op">=</span> y_base <span class="op">*</span> (<span class="dv">10</span><span class="op">**</span><span class="dv">1</span>)</span> +<span id="cb3-6"><a href="#cb3-6" aria-hidden="true" tabindex="-1"></a>r3 <span class="op">=</span> y_base <span class="op">*</span> (<span class="dv">10</span><span class="op">**</span><span class="dv">2</span>)</span> +<span id="cb3-7"><a href="#cb3-7" aria-hidden="true" tabindex="-1"></a>r4 <span class="op">=</span> y_base <span class="op">*</span> (<span class="dv">10</span><span class="op">**</span><span class="dv">2</span>)</span> +<span id="cb3-8"><a href="#cb3-8" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb3-9"><a href="#cb3-9" aria-hidden="true" tabindex="-1"></a>ys <span class="op">=</span> np.concatenate([r1, r2, r3, r4])</span> +<span id="cb3-10"><a href="#cb3-10" aria-hidden="true" tabindex="-1"></a>ds <span class="op">=</span> np.tile(ds, <span class="dv">4</span>)</span> +<span id="cb3-11"><a href="#cb3-11" aria-hidden="true" tabindex="-1"></a>unique_ids <span class="op">=</span> [<span class="st">'r1'</span>] <span class="op">*</span> <span class="dv">8</span> <span class="op">+</span> [<span class="st">'r2'</span>] <span class="op">*</span> <span class="dv">8</span> <span class="op">+</span> [<span class="st">'r3'</span>] <span class="op">*</span> <span class="dv">8</span> <span class="op">+</span> [<span class="st">'r4'</span>] <span class="op">*</span> <span class="dv">8</span></span> +<span id="cb3-12"><a href="#cb3-12" aria-hidden="true" tabindex="-1"></a>top_level <span class="op">=</span> <span class="st">'Australia'</span></span> +<span id="cb3-13"><a href="#cb3-13" aria-hidden="true" tabindex="-1"></a>middle_level <span class="op">=</span> [<span class="st">'State1'</span>] <span class="op">*</span> <span class="dv">16</span> <span class="op">+</span> [<span class="st">'State2'</span>] <span class="op">*</span> <span class="dv">16</span></span> +<span id="cb3-14"><a href="#cb3-14" aria-hidden="true" tabindex="-1"></a>bottom_level <span class="op">=</span> unique_ids</span> +<span id="cb3-15"><a href="#cb3-15" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb3-16"><a href="#cb3-16" aria-hidden="true" tabindex="-1"></a>bottom_df <span class="op">=</span> <span class="bu">dict</span>(ds<span class="op">=</span>ds,</span> +<span id="cb3-17"><a href="#cb3-17" aria-hidden="true" tabindex="-1"></a> top_level<span class="op">=</span>top_level, </span> +<span id="cb3-18"><a href="#cb3-18" aria-hidden="true" tabindex="-1"></a> middle_level<span class="op">=</span>middle_level, </span> +<span id="cb3-19"><a href="#cb3-19" aria-hidden="true" tabindex="-1"></a> bottom_level<span class="op">=</span>bottom_level,</span> +<span id="cb3-20"><a href="#cb3-20" aria-hidden="true" tabindex="-1"></a> y<span class="op">=</span>ys)</span> +<span id="cb3-21"><a href="#cb3-21" aria-hidden="true" tabindex="-1"></a>bottom_df <span class="op">=</span> pd.DataFrame(bottom_df)</span> +<span id="cb3-22"><a href="#cb3-22" aria-hidden="true" tabindex="-1"></a>bottom_df.groupby(<span class="st">'bottom_level'</span>).head(<span class="dv">2</span>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<div> + + +<table class="dataframe table table-sm table-striped small" data-quarto-postprocess="true" data-border="1"> +<thead> +<tr class="header"> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th">ds</th> +<th data-quarto-table-cell-role="th">top_level</th> +<th data-quarto-table-cell-role="th">middle_level</th> +<th data-quarto-table-cell-role="th">bottom_level</th> +<th data-quarto-table-cell-role="th">y</th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td data-quarto-table-cell-role="th">0</td> +<td>2000-01-01</td> +<td>Australia</td> +<td>State1</td> +<td>r1</td> +<td>10</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">1</td> +<td>2000-02-01</td> +<td>Australia</td> +<td>State1</td> +<td>r1</td> +<td>20</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">8</td> +<td>2000-01-01</td> +<td>Australia</td> +<td>State1</td> +<td>r2</td> +<td>10</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">9</td> +<td>2000-02-01</td> +<td>Australia</td> +<td>State1</td> +<td>r2</td> +<td>20</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">16</td> +<td>2000-01-01</td> +<td>Australia</td> +<td>State2</td> +<td>r3</td> +<td>100</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">17</td> +<td>2000-02-01</td> +<td>Australia</td> +<td>State2</td> +<td>r3</td> +<td>200</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">24</td> +<td>2000-01-01</td> +<td>Australia</td> +<td>State2</td> +<td>r4</td> +<td>100</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">25</td> +<td>2000-02-01</td> +<td>Australia</td> +<td>State2</td> +<td>r4</td> +<td>200</td> +</tr> +</tbody> +</table> + +</div> +</div> +</div> +<p>The previously introduced hierarchical series <span class="math inline">\(\mathbf{y}_{[a,b]\tau}\)</span> is captured within the <code>Y_hier_df</code> dataframe.</p> +<p>The aggregation constraints matrix <span class="math inline">\(\mathbf{S}_{[a][b]}\)</span> is captured within the <code>S_df</code> dataframe.</p> +<p>Finally the <code>tags</code> contains a list within <code>Y_hier_df</code> composing each hierarchical level, for example the <code>tags['top_level']</code> contains <code>Australia</code>ās aggregated series index.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb4"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> hierarchicalforecast.utils <span class="im">import</span> aggregate</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb5"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="co"># Create hierarchical structure and constraints</span></span> +<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>hierarchy_levels <span class="op">=</span> [[<span class="st">'top_level'</span>],</span> +<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a> [<span class="st">'top_level'</span>, <span class="st">'middle_level'</span>],</span> +<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a> [<span class="st">'top_level'</span>, <span class="st">'middle_level'</span>, <span class="st">'bottom_level'</span>]]</span> +<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>Y_hier_df, S_df, tags <span class="op">=</span> aggregate(df<span class="op">=</span>bottom_df, spec<span class="op">=</span>hierarchy_levels)</span> +<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a>Y_hier_df <span class="op">=</span> Y_hier_df.reset_index()</span> +<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(<span class="st">'S_df.shape'</span>, S_df.shape)</span> +<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(<span class="st">'Y_hier_df.shape'</span>, Y_hier_df.shape)</span> +<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a><span class="bu">print</span>(<span class="st">"tags['top_level']"</span>, tags[<span class="st">'top_level'</span>])</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-stdout"> +<pre><code>S_df.shape (7, 4) +Y_hier_df.shape (56, 3) +tags['top_level'] ['Australia']</code></pre> +</div> +<div class="cell-output cell-output-stderr"> +<pre><code>/Users/cchallu/opt/anaconda3/envs/hierarchicalforecast/lib/python3.10/site-packages/sklearn/preprocessing/_encoders.py:828: FutureWarning: `sparse` was renamed to `sparse_output` in version 1.2 and will be removed in 1.4. `sparse_output` is ignored unless you leave `sparse` to its default value. + warnings.warn(</code></pre> +</div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb8"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a>Y_hier_df.groupby(<span class="st">'unique_id'</span>).head(<span class="dv">2</span>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<div> + + +<table class="dataframe table table-sm table-striped small" data-quarto-postprocess="true" data-border="1"> +<thead> +<tr class="header"> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th">unique_id</th> +<th data-quarto-table-cell-role="th">ds</th> +<th data-quarto-table-cell-role="th">y</th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td data-quarto-table-cell-role="th">0</td> +<td>Australia</td> +<td>2000-01-01</td> +<td>220.0</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">1</td> +<td>Australia</td> +<td>2000-02-01</td> +<td>440.0</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">8</td> +<td>Australia/State1</td> +<td>2000-01-01</td> +<td>20.0</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">9</td> +<td>Australia/State1</td> +<td>2000-02-01</td> +<td>40.0</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">16</td> +<td>Australia/State2</td> +<td>2000-01-01</td> +<td>200.0</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">17</td> +<td>Australia/State2</td> +<td>2000-02-01</td> +<td>400.0</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">24</td> +<td>Australia/State1/r1</td> +<td>2000-01-01</td> +<td>10.0</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">25</td> +<td>Australia/State1/r1</td> +<td>2000-02-01</td> +<td>20.0</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">32</td> +<td>Australia/State1/r2</td> +<td>2000-01-01</td> +<td>10.0</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">33</td> +<td>Australia/State1/r2</td> +<td>2000-02-01</td> +<td>20.0</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">40</td> +<td>Australia/State2/r3</td> +<td>2000-01-01</td> +<td>100.0</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">41</td> +<td>Australia/State2/r3</td> +<td>2000-02-01</td> +<td>200.0</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">48</td> +<td>Australia/State2/r4</td> +<td>2000-01-01</td> +<td>100.0</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">49</td> +<td>Australia/State2/r4</td> +<td>2000-02-01</td> +<td>200.0</td> +</tr> +</tbody> +</table> + +</div> +</div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb9"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a>S_df</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<div> + + +<table class="dataframe table table-sm table-striped small" data-quarto-postprocess="true" data-border="1"> +<thead> +<tr class="header"> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th">Australia/State1/r1</th> +<th data-quarto-table-cell-role="th">Australia/State1/r2</th> +<th data-quarto-table-cell-role="th">Australia/State2/r3</th> +<th data-quarto-table-cell-role="th">Australia/State2/r4</th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td data-quarto-table-cell-role="th">Australia</td> +<td>1.0</td> +<td>1.0</td> +<td>1.0</td> +<td>1.0</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">Australia/State1</td> +<td>1.0</td> +<td>1.0</td> +<td>0.0</td> +<td>0.0</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">Australia/State2</td> +<td>0.0</td> +<td>0.0</td> +<td>1.0</td> +<td>1.0</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">Australia/State1/r1</td> +<td>1.0</td> +<td>0.0</td> +<td>0.0</td> +<td>0.0</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">Australia/State1/r2</td> +<td>0.0</td> +<td>1.0</td> +<td>0.0</td> +<td>0.0</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">Australia/State2/r3</td> +<td>0.0</td> +<td>0.0</td> +<td>1.0</td> +<td>0.0</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">Australia/State2/r4</td> +<td>0.0</td> +<td>0.0</td> +<td>0.0</td> +<td>1.0</td> +</tr> +</tbody> +</table> + +</div> +</div> +</div> +</section> +<section id="base-predictions" class="level3"> +<h3 class="anchored" data-anchor-id="base-predictions">Base Predictions</h3> +<p>Next, we compute the <em>base forecast</em> for each time series using the <code>naive</code> model. Observe that <code>Y_hat_df</code> contains the forecasts but they are not coherent.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb10"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> statsforecast.models <span class="im">import</span> Naive</span> +<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> statsforecast.core <span class="im">import</span> StatsForecast</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb11"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a><span class="co"># Split train/test sets</span></span> +<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a>Y_test_df <span class="op">=</span> Y_hier_df.groupby(<span class="st">'unique_id'</span>).tail(<span class="dv">4</span>)</span> +<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a>Y_train_df <span class="op">=</span> Y_hier_df.drop(Y_test_df.index)</span> +<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a><span class="co"># Compute base Naive predictions</span></span> +<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a><span class="co"># Careful identifying correct data freq, this data quarterly 'Q'</span></span> +<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a>fcst <span class="op">=</span> StatsForecast(df<span class="op">=</span>Y_train_df,</span> +<span id="cb11-8"><a href="#cb11-8" aria-hidden="true" tabindex="-1"></a> models<span class="op">=</span>[Naive()],</span> +<span id="cb11-9"><a href="#cb11-9" aria-hidden="true" tabindex="-1"></a> freq<span class="op">=</span><span class="st">'Q'</span>, n_jobs<span class="op">=-</span><span class="dv">1</span>)</span> +<span id="cb11-10"><a href="#cb11-10" aria-hidden="true" tabindex="-1"></a>Y_hat_df <span class="op">=</span> fcst.forecast(h<span class="op">=</span><span class="dv">4</span>, fitted<span class="op">=</span><span class="va">True</span>)</span> +<span id="cb11-11"><a href="#cb11-11" aria-hidden="true" tabindex="-1"></a>Y_fitted_df <span class="op">=</span> fcst.forecast_fitted_values()</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +</section> +<section id="reconciliation" class="level3"> +<h3 class="anchored" data-anchor-id="reconciliation">Reconciliation</h3> +<div class="cell"> +<div class="sourceCode cell-code" id="cb12"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> hierarchicalforecast.methods <span class="im">import</span> BottomUp</span> +<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> hierarchicalforecast.core <span class="im">import</span> HierarchicalReconciliation</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb13"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="co"># You can select a reconciler from our collection</span></span> +<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a>reconcilers <span class="op">=</span> [BottomUp()] <span class="co"># MinTrace(method='mint_shrink')</span></span> +<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a>hrec <span class="op">=</span> HierarchicalReconciliation(reconcilers<span class="op">=</span>reconcilers)</span> +<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a>Y_rec_df <span class="op">=</span> hrec.reconcile(Y_hat_df<span class="op">=</span>Y_hat_df, </span> +<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a> Y_df<span class="op">=</span>Y_fitted_df,</span> +<span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a> S<span class="op">=</span>S_df, tags<span class="op">=</span>tags)</span> +<span id="cb13-8"><a href="#cb13-8" aria-hidden="true" tabindex="-1"></a>Y_rec_df.groupby(<span class="st">'unique_id'</span>).head(<span class="dv">2</span>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<div> + + +<table class="dataframe table table-sm table-striped small" data-quarto-postprocess="true" data-border="1"> +<thead> +<tr class="header"> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th">ds</th> +<th data-quarto-table-cell-role="th">Naive</th> +<th data-quarto-table-cell-role="th">Naive/BottomUp</th> +</tr> +<tr class="odd"> +<th data-quarto-table-cell-role="th">unique_id</th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td data-quarto-table-cell-role="th">Australia</td> +<td>2000-06-30</td> +<td>880.0</td> +<td>880.0</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">Australia</td> +<td>2000-09-30</td> +<td>880.0</td> +<td>880.0</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">Australia/State1</td> +<td>2000-06-30</td> +<td>80.0</td> +<td>80.0</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">Australia/State1</td> +<td>2000-09-30</td> +<td>80.0</td> +<td>80.0</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">Australia/State2</td> +<td>2000-06-30</td> +<td>800.0</td> +<td>800.0</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">Australia/State2</td> +<td>2000-09-30</td> +<td>800.0</td> +<td>800.0</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">Australia/State1/r1</td> +<td>2000-06-30</td> +<td>40.0</td> +<td>40.0</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">Australia/State1/r1</td> +<td>2000-09-30</td> +<td>40.0</td> +<td>40.0</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">Australia/State1/r2</td> +<td>2000-06-30</td> +<td>40.0</td> +<td>40.0</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">Australia/State1/r2</td> +<td>2000-09-30</td> +<td>40.0</td> +<td>40.0</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">Australia/State2/r3</td> +<td>2000-06-30</td> +<td>400.0</td> +<td>400.0</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">Australia/State2/r3</td> +<td>2000-09-30</td> +<td>400.0</td> +<td>400.0</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">Australia/State2/r4</td> +<td>2000-06-30</td> +<td>400.0</td> +<td>400.0</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">Australia/State2/r4</td> +<td>2000-09-30</td> +<td>400.0</td> +<td>400.0</td> +</tr> +</tbody> +</table> + +</div> +</div> +</div> +</section> +</section> +<section id="references" class="level2"> +<h2 class="anchored" data-anchor-id="references">References</h2> +<ul> +<li><a href="https://otexts.com/fpp3/hierarchical.html">Hyndman, R.J., & Athanasopoulos, G. (2021). āForecasting: principles and practice, 3rd edition: Chapter 11: Forecasting hierarchical and grouped series.ā. OTexts: Melbourne, Australia. OTexts.com/fpp3 Accessed on July 2022.</a><br></li> +<li><a href="http://www.jstor.org/stable/1815532">Orcutt, G.H., Watts, H.W., & Edwards, J.B.(1968). Data aggregation and information loss. The American Economic Review, 58 , 773{787).</a><br></li> +<li><a href="https://onlinelibrary.wiley.com/doi/abs/10.1002/for.3980090304">Disaggregation methods to expedite product line forecasting. Journal of Forecasting, 9 , 233ā254. doi:10.1002/for.3980090304.</a><br></li> +<li><a href="https://robjhyndman.com/publications/mint/">Wickramasuriya, S. L., Athanasopoulos, G., & Hyndman, R. J. (2019). "Optimal forecast reconciliation for hierarchical and grouped time series through trace minimization". Journal of the American Statistical Association, 114 , 804ā819. doi:10.1080/01621459.2018.1448825.</a><br></li> +<li><a href="https://doi.org/10.1145/3292500.3330976">Ben Taieb, S., & Koo, B. (2019). Regularized regression for hierarchical forecasting without unbiasedness conditions. In Proceedings of the 25th ACM SIGKDD International Conference on Knowledge Discovery & Data Mining KDD ā19 (p. 1337{1347). New York, NY, USA: Association for Computing Machinery.</a><br></li> +</ul> + + +</section> + +<p>If you find the code useful, please ā us on <a href="https://github.com/nixtla/hierarchicalforecast">Github</a></p></main> <!-- /main --> +<script id="quarto-html-after-body" type="application/javascript"> +window.document.addEventListener("DOMContentLoaded", function (event) { + const toggleBodyColorMode = (bsSheetEl) => { + const mode = bsSheetEl.getAttribute("data-mode"); + const bodyEl = window.document.querySelector("body"); + if (mode === "dark") { + bodyEl.classList.add("quarto-dark"); + bodyEl.classList.remove("quarto-light"); + } else { + bodyEl.classList.add("quarto-light"); + bodyEl.classList.remove("quarto-dark"); + } + } + const toggleBodyColorPrimary = () => { + const bsSheetEl = window.document.querySelector("link#quarto-bootstrap"); + if (bsSheetEl) { + toggleBodyColorMode(bsSheetEl); + } + } + toggleBodyColorPrimary(); + const icon = "ī§"; + const anchorJS = new window.AnchorJS(); + anchorJS.options = { + placement: 'right', + icon: icon + }; + anchorJS.add('.anchored'); + const isCodeAnnotation = (el) => { + for (const clz of el.classList) { + if (clz.startsWith('code-annotation-')) { + return true; + } + } + return false; + } + const clipboard = new window.ClipboardJS('.code-copy-button', { + text: function(trigger) { + const codeEl = trigger.previousElementSibling.cloneNode(true); + for (const childEl of codeEl.children) { + if (isCodeAnnotation(childEl)) { + childEl.remove(); + } + } + return codeEl.innerText; + } + }); + clipboard.on('success', function(e) { + // button target + const button = e.trigger; + // don't keep focus + button.blur(); + // flash "checked" + button.classList.add('code-copy-button-checked'); + var currentTitle = button.getAttribute("title"); + button.setAttribute("title", "Copied!"); + let tooltip; + if (window.bootstrap) { + button.setAttribute("data-bs-toggle", "tooltip"); + button.setAttribute("data-bs-placement", "left"); + button.setAttribute("data-bs-title", "Copied!"); + tooltip = new bootstrap.Tooltip(button, + { trigger: "manual", + customClass: "code-copy-button-tooltip", + offset: [0, -8]}); + tooltip.show(); + } + setTimeout(function() { + if (tooltip) { + tooltip.hide(); + button.removeAttribute("data-bs-title"); + button.removeAttribute("data-bs-toggle"); + button.removeAttribute("data-bs-placement"); + } + button.setAttribute("title", currentTitle); + button.classList.remove('code-copy-button-checked'); + }, 1000); + // clear code selection + e.clearSelection(); + }); + function tippyHover(el, contentFn) { + const config = { + allowHTML: true, + content: contentFn, + maxWidth: 500, + delay: 100, + arrow: false, + appendTo: function(el) { + return el.parentElement; + }, + interactive: true, + interactiveBorder: 10, + theme: 'quarto', + placement: 'bottom-start' + }; + window.tippy(el, config); + } + const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]'); + for (var i=0; i<noterefs.length; i++) { + const ref = noterefs[i]; + tippyHover(ref, function() { + // use id or data attribute instead here + let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href'); + try { href = new URL(href).hash; } catch {} + const id = href.replace(/^#\/?/, ""); + const note = window.document.getElementById(id); + return note.innerHTML; + }); + } + let selectedAnnoteEl; + const selectorForAnnotation = ( cell, annotation) => { + let cellAttr = 'data-code-cell="' + cell + '"'; + let lineAttr = 'data-code-annotation="' + annotation + '"'; + const selector = 'span[' + cellAttr + '][' + lineAttr + ']'; + return selector; + } + const selectCodeLines = (annoteEl) => { + const doc = window.document; + const targetCell = annoteEl.getAttribute("data-target-cell"); + const targetAnnotation = annoteEl.getAttribute("data-target-annotation"); + const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation)); + const lines = annoteSpan.getAttribute("data-code-lines").split(","); + const lineIds = lines.map((line) => { + return targetCell + "-" + line; + }) + let top = null; + let height = null; + let parent = null; + if (lineIds.length > 0) { + //compute the position of the single el (top and bottom and make a div) + const el = window.document.getElementById(lineIds[0]); + top = el.offsetTop; + height = el.offsetHeight; + parent = el.parentElement.parentElement; + if (lineIds.length > 1) { + const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]); + const bottom = lastEl.offsetTop + lastEl.offsetHeight; + height = bottom - top; + } + if (top !== null && height !== null && parent !== null) { + // cook up a div (if necessary) and position it + let div = window.document.getElementById("code-annotation-line-highlight"); + if (div === null) { + div = window.document.createElement("div"); + div.setAttribute("id", "code-annotation-line-highlight"); + div.style.position = 'absolute'; + parent.appendChild(div); + } + div.style.top = top - 2 + "px"; + div.style.height = height + 4 + "px"; + let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter"); + if (gutterDiv === null) { + gutterDiv = window.document.createElement("div"); + gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter"); + gutterDiv.style.position = 'absolute'; + const codeCell = window.document.getElementById(targetCell); + const gutter = codeCell.querySelector('.code-annotation-gutter'); + gutter.appendChild(gutterDiv); + } + gutterDiv.style.top = top - 2 + "px"; + gutterDiv.style.height = height + 4 + "px"; + } + selectedAnnoteEl = annoteEl; + } + }; + const unselectCodeLines = () => { + const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"]; + elementsIds.forEach((elId) => { + const div = window.document.getElementById(elId); + if (div) { + div.remove(); + } + }); + selectedAnnoteEl = undefined; + }; + // Attach click handler to the DT + const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); + for (const annoteDlNode of annoteDls) { + annoteDlNode.addEventListener('click', (event) => { + const clickedEl = event.target; + if (clickedEl !== selectedAnnoteEl) { + unselectCodeLines(); + const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active'); + if (activeEl) { + activeEl.classList.remove('code-annotation-active'); + } + selectCodeLines(clickedEl); + clickedEl.classList.add('code-annotation-active'); + } else { + // Unselect the line + unselectCodeLines(); + clickedEl.classList.remove('code-annotation-active'); + } + }); + } + const findCites = (el) => { + const parentEl = el.parentElement; + if (parentEl) { + const cites = parentEl.dataset.cites; + if (cites) { + return { + el, + cites: cites.split(' ') + }; + } else { + return findCites(el.parentElement) + } + } else { + return undefined; + } + }; + var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]'); + for (var i=0; i<bibliorefs.length; i++) { + const ref = bibliorefs[i]; + const citeInfo = findCites(ref); + if (citeInfo) { + tippyHover(citeInfo.el, function() { + var popup = window.document.createElement('div'); + citeInfo.cites.forEach(function(cite) { + var citeDiv = window.document.createElement('div'); + citeDiv.classList.add('hanging-indent'); + citeDiv.classList.add('csl-entry'); + var biblioDiv = window.document.getElementById('ref-' + cite); + if (biblioDiv) { + citeDiv.innerHTML = biblioDiv.innerHTML; + } + popup.appendChild(citeDiv); + }); + return popup.innerHTML; + }); + } + } +}); +</script> +</div> <!-- /content --> + + + +</body></html> \ No newline at end of file diff --git a/examples/mlframeworksexample.html b/examples/mlframeworksexample.html new file mode 100644 index 00000000..71359b5c --- /dev/null +++ b/examples/mlframeworksexample.html @@ -0,0 +1,1991 @@ +<!DOCTYPE html> +<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head> + +<meta charset="utf-8"> +<meta name="generator" content="quarto-1.3.450"> + +<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes"> + + +<title>hierarchicalforecast - Neural/MLForecast</title> +<style> +code{white-space: pre-wrap;} +span.smallcaps{font-variant: small-caps;} +div.columns{display: flex; gap: min(4vw, 1.5em);} +div.column{flex: auto; overflow-x: auto;} +div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;} +ul.task-list{list-style: none;} +ul.task-list li input[type="checkbox"] { + width: 0.8em; + margin: 0 0.8em 0.2em -1em; /* quarto-specific, see https://github.com/quarto-dev/quarto-cli/issues/4556 */ + vertical-align: middle; +} +/* CSS for syntax highlighting */ +pre > code.sourceCode { white-space: pre; position: relative; } +pre > code.sourceCode > span { display: inline-block; line-height: 1.25; } +pre > code.sourceCode > span:empty { height: 1.2em; } +.sourceCode { overflow: visible; } +code.sourceCode > span { color: inherit; text-decoration: inherit; } +div.sourceCode { margin: 1em 0; } +pre.sourceCode { margin: 0; } +@media screen { +div.sourceCode { overflow: auto; } +} +@media print { +pre > code.sourceCode { white-space: pre-wrap; } +pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; } +} +pre.numberSource code + { counter-reset: source-line 0; } +pre.numberSource code > span + { position: relative; left: -4em; counter-increment: source-line; } +pre.numberSource code > span > a:first-child::before + { content: counter(source-line); + position: relative; left: -1em; text-align: right; vertical-align: baseline; + border: none; display: inline-block; + -webkit-touch-callout: none; -webkit-user-select: none; + -khtml-user-select: none; -moz-user-select: none; + -ms-user-select: none; user-select: none; + padding: 0 4px; width: 4em; + } +pre.numberSource { margin-left: 3em; padding-left: 4px; } +div.sourceCode + { } +@media screen { +pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; } +} +</style> + + +<script src="../site_libs/quarto-nav/quarto-nav.js"></script> +<script src="../site_libs/quarto-nav/headroom.min.js"></script> +<script src="../site_libs/clipboard/clipboard.min.js"></script> +<script src="../site_libs/quarto-search/autocomplete.umd.js"></script> +<script src="../site_libs/quarto-search/fuse.min.js"></script> +<script src="../site_libs/quarto-search/quarto-search.js"></script> +<meta name="quarto:offset" content="../"> +<link href="../favicon_png.png" rel="icon" type="image/png"> +<script src="../site_libs/quarto-html/quarto.js"></script> +<script src="../site_libs/quarto-html/popper.min.js"></script> +<script src="../site_libs/quarto-html/tippy.umd.min.js"></script> +<script src="../site_libs/quarto-html/anchor.min.js"></script> +<link href="../site_libs/quarto-html/tippy.css" rel="stylesheet"> +<link href="../site_libs/quarto-html/quarto-syntax-highlighting.css" rel="stylesheet" id="quarto-text-highlighting-styles"> +<script src="../site_libs/bootstrap/bootstrap.min.js"></script> +<link href="../site_libs/bootstrap/bootstrap-icons.css" rel="stylesheet"> +<link href="../site_libs/bootstrap/bootstrap.min.css" rel="stylesheet" id="quarto-bootstrap" data-mode="light"> +<script id="quarto-search-options" type="application/json">{ + "location": "navbar", + "copy-button": false, + "collapse-after": 3, + "panel-placement": "end", + "type": "overlay", + "limit": 20, + "language": { + "search-no-results-text": "No results", + "search-matching-documents-text": "matching documents", + "search-copy-link-title": "Copy link to search", + "search-hide-matches-text": "Hide additional matches", + "search-more-match-text": "more match in this document", + "search-more-matches-text": "more matches in this document", + "search-clear-button-title": "Clear", + "search-detached-cancel-button-title": "Cancel", + "search-submit-button-title": "Submit", + "search-label": "Search" + } +}</script> +<script async="" src="https://www.googletagmanager.com/gtag/js?id=G-NXJNCVR18L"></script> + +<script type="text/javascript"> + +window.dataLayer = window.dataLayer || []; +function gtag(){dataLayer.push(arguments);} +gtag('js', new Date()); +gtag('config', 'G-NXJNCVR18L', { 'anonymize_ip': true}); +</script> +<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js" integrity="sha512-c3Nl8+7g4LMSTdrm621y7kf9v3SDPnhxLNhcjFJbKECVnmZHTdo+IRO05sNLTH/D3vA6u1X32ehoLC7WFVdheg==" crossorigin="anonymous"></script> +<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js" integrity="sha512-bLT0Qm9VnAYZDflyKcBaQ2gg0hSYNQrJ8RilYldYQ1FxQYoCLtUjuuRuZo+fjqhx/qtq/1itJ0C2ejDxltZVFg==" crossorigin="anonymous"></script> +<script type="application/javascript">define('jquery', [],function() {return window.jQuery;})</script> +<script src="https://unpkg.com/@jupyter-widgets/html-manager@*/dist/embed-amd.js" crossorigin="anonymous"></script> + + <script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script> + <script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml-full.js" type="text/javascript"></script> + +<link rel="stylesheet" href="../styles.css"> +<meta property="og:title" content="hierarchicalforecast - Neural/MLForecast"> +<meta property="og:description" content=""> +<meta property="og:image" content="https://colab.research.google.com/assets/colab-badge.svg"> +<meta property="og:site-name" content="hierarchicalforecast"> +<meta name="twitter:title" content="hierarchicalforecast - Neural/MLForecast"> +<meta name="twitter:description" content=""> +<meta name="twitter:image" content="https://colab.research.google.com/assets/colab-badge.svg"> +<meta name="twitter:card" content="summary_large_image"> +</head> + +<body class="nav-sidebar floating nav-fixed"> + +<div id="quarto-search-results"></div> + <header id="quarto-header" class="headroom fixed-top"> + <nav class="navbar navbar-expand-lg navbar-dark "> + <div class="navbar-container container-fluid"> + <div class="navbar-brand-container"> + <a class="navbar-brand" href="../index.html"> + <span class="navbar-title">hierarchicalforecast</span> + </a> + </div> + <div id="quarto-search" class="" title="Search"></div> + <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + <span class="navbar-toggler-icon"></span> +</button> + <div class="collapse navbar-collapse" id="navbarCollapse"> + <ul class="navbar-nav navbar-nav-scroll me-auto"> + <li class="nav-item"> + <a class="nav-link active" href="../examples/tourismsmall.html" rel="" target="" aria-current="page"> + <span class="menu-text">Get Started</span></a> + </li> + <li class="nav-item dropdown "> + <a class="nav-link dropdown-toggle" href="#" id="nav-menu-nixtlaverse" role="button" data-bs-toggle="dropdown" aria-expanded="false" rel="" target=""> + <span class="menu-text">NixtlaVerse</span> + </a> + <ul class="dropdown-menu" aria-labelledby="nav-menu-nixtlaverse"> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/mlforecast" rel="" target=""> + <span class="dropdown-text">MLForecast š¤</span></a> + </li> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/neuralforecast" rel="" target=""> + <span class="dropdown-text">NeuralForecast š§ </span></a> + </li> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/statsforecast" rel="" target=""> + <span class="dropdown-text">StatsForecast ā”ļø</span></a> + </li> + </ul> + </li> + <li class="nav-item dropdown "> + <a class="nav-link dropdown-toggle" href="#" id="nav-menu-help" role="button" data-bs-toggle="dropdown" aria-expanded="false" rel="" target=""> + <span class="menu-text">Help</span> + </a> + <ul class="dropdown-menu" aria-labelledby="nav-menu-help"> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/hierarchicalforecast/issues/new/choose" rel="" target=""><i class="bi bi-bug" role="img"> +</i> + <span class="dropdown-text">Report an Issue</span></a> + </li> + <li> + <a class="dropdown-item" href="https://join.slack.com/t/nixtlacommunity/shared_invite/zt-1kd5m5db7-7OOfy0xVNf1PcvCiAPWvPw" rel="" target=""><i class="bi bi-chat-right-text" role="img"> +</i> + <span class="dropdown-text">Join our Slack</span></a> + </li> + </ul> + </li> +</ul> + <ul class="navbar-nav navbar-nav-scroll ms-auto"> + <li class="nav-item compact"> + <a class="nav-link" href="https://github.com/nixtla/hierarchicalforecast" rel="" target=""><i class="bi bi-github" role="img"> +</i> + <span class="menu-text"></span></a> + </li> + <li class="nav-item compact"> + <a class="nav-link" href="https://twitter.com/nixtlainc" rel="" target=""><i class="bi bi-twitter" role="img" aria-label="Nixtla Twitter"> +</i> + <span class="menu-text"></span></a> + </li> +</ul> + <div class="quarto-navbar-tools"> +</div> + </div> <!-- /navcollapse --> + </div> <!-- /container-fluid --> + </nav> + <nav class="quarto-secondary-nav"> + <div class="container-fluid d-flex"> + <button type="button" class="quarto-btn-toggle btn" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + <i class="bi bi-layout-text-sidebar-reverse"></i> + </button> + <nav class="quarto-page-breadcrumbs" aria-label="breadcrumb"><ol class="breadcrumb"><li class="breadcrumb-item">Tutorials</li><li class="breadcrumb-item"><a href="../examples/hierarchicalforecast-gluonts.html">ML Forecast Reconciliation</a></li><li class="breadcrumb-item"><a href="../examples/mlframeworksexample.html">Neural/MLForecast</a></li></ol></nav> + <a class="flex-grow-1" role="button" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + </a> + </div> + </nav> +</header> +<!-- content --> +<div id="quarto-content" class="quarto-container page-columns page-rows-contents page-layout-article page-navbar"> +<!-- sidebar --> + <nav id="quarto-sidebar" class="sidebar collapse collapse-horizontal sidebar-navigation floating overflow-auto"> + <div class="sidebar-menu-container"> + <ul class="list-unstyled mt-1"> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../index.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Hierarchical Forecast š</span></a> + </div> +</li> + <li class="px-0"><hr class="sidebar-divider hi "></li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-1" aria-expanded="false"> + <span class="menu-text">Getting Started</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-1" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-1" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/installation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Install</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/tourismsmall.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Reconciliation Quick Start</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/introduction.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Introduction</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-2" aria-expanded="true"> + <span class="menu-text">Tutorials</span></a> + <a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-2" aria-expanded="true" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-2" class="collapse list-unstyled sidebar-section depth1 show"> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-3" aria-expanded="false"> + <span class="menu-text">Point Reconciliation</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-3" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-3" class="collapse list-unstyled sidebar-section depth2 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Geographical Aggregation (Tourism)</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australianprisonpopulation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Geographical Aggregation (Prison Population)</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/nonnegativereconciliation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Non-Negative MinTrace</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-4" aria-expanded="false"> + <span class="menu-text">Probabilistic Reconciliation</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-4" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-4" class="collapse list-unstyled sidebar-section depth2 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Normality</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism-bootstraped-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Bootstrap</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism-permbu-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">PERMBU</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/tourismlarge-evaluation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Probabilistic Forecast Evaluation</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-5" aria-expanded="true"> + <span class="menu-text">ML Forecast Reconciliation</span></a> + <a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-5" aria-expanded="true" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-5" class="collapse list-unstyled sidebar-section depth2 show"> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/hierarchicalforecast-gluonts.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">GluonTS</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/mlframeworksexample.html" class="sidebar-item-text sidebar-link active"> + <span class="menu-text">Neural/MLForecast</span></a> + </div> +</li> + </ul> + </li> + </ul> + </li> + <li class="sidebar-item"> + <span class="menu-text">Methods</span> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-6" aria-expanded="false"> + <span class="menu-text">API Reference</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-6" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-6" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../core.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Core </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../methods.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Reconciliation Methods </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../probabilistic_methods.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Probabilistic Methods </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../evaluation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Hierarchical Evaluation</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../utils.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Aggregation/Visualization Utils</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-7" aria-expanded="false"> + <span class="menu-text">Community</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-7" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-7" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item"> + <span class="menu-text">Contributing</span> + </li> + </ul> + </li> + </ul> + </div> +</nav> +<div id="quarto-sidebar-glass" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass"></div> +<!-- margin-sidebar --> + <div id="quarto-margin-sidebar" class="sidebar margin-sidebar"> + <nav id="TOC" role="doc-toc" class="toc-active"> + <h2 id="toc-title">On this page</h2> + + <ul> + <li><a href="#installing-packages" id="toc-installing-packages" class="nav-link active" data-scroll-target="#installing-packages">1. Installing packages</a></li> + <li><a href="#load-hierarchical-dataset" id="toc-load-hierarchical-dataset" class="nav-link" data-scroll-target="#load-hierarchical-dataset">2. Load hierarchical dataset</a></li> + <li><a href="#fit-and-predict-models" id="toc-fit-and-predict-models" class="nav-link" data-scroll-target="#fit-and-predict-models">3. Fit and Predict Models</a></li> + <li><a href="#reconcile-predictions" id="toc-reconcile-predictions" class="nav-link" data-scroll-target="#reconcile-predictions">4. Reconcile Predictions</a></li> + <li><a href="#evaluation" id="toc-evaluation" class="nav-link" data-scroll-target="#evaluation">5. Evaluation</a></li> + <li><a href="#visualizations" id="toc-visualizations" class="nav-link" data-scroll-target="#visualizations">6. Visualizations</a></li> + </ul> +<div class="toc-actions"><div><i class="bi bi-github"></i></div><div class="action-links"><p><a href="https://github.com/Nixtla/hierarchicalforecast/issues/new" class="toc-action">Report an issue</a></p></div></div></nav> + </div> +<!-- main --> +<main class="content" id="quarto-document-content"> + +<header id="title-block-header" class="quarto-title-block default"> +<div class="quarto-title"> +<h1 class="title">Neural/MLForecast</h1> +</div> + + + +<div class="quarto-title-meta"> + + + + + </div> + + +</header> + +<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! --> +<p>This example notebook demonstrates the compatibility of HierarchicalForecastās reconciliation methods with popular machine-learning libraries, specifically <a href="https://github.com/Nixtla/neuralforecast">NeuralForecast</a> and <a href="https://github.com/Nixtla/mlforecast">MLForecast</a>.</p> +<p>The notebook utilizes NBEATS and XGBRegressor models to create base forecasts for the TourismLarge Hierarchical Dataset. After that, we use HierarchicalForecast to reconcile the base predictions.</p> +<p><strong>References</strong><br> - <a href="https://arxiv.org/abs/1905.10437">Boris N. Oreshkin, Dmitri Carpov, Nicolas Chapados, Yoshua Bengio (2019). āN-BEATS: Neural basis expansion analysis for interpretable time series forecastingā. url: https://arxiv.org/abs/1905.10437</a><br> - <a href="https://doi.org/10.1145/2939672.2939785">Tianqi Chen and Carlos Guestrin. āXGBoost: A Scalable Tree Boosting Systemā. In: Proceedings of the 22nd ACM SIGKDD International Conference on Knowledge Discovery and Data Mining. KDD ā16. San Francisco, California, USA: Association for Computing Machinery, 2016, pp. 785ā794. isbn: 9781450342322. doi: 10.1145/2939672.2939785. url: https://doi.org/10.1145/2939672.2939785 (cit. on p. 26).</a><br></p> +<p>You can run these experiments using CPU or GPU with Google Colab.</p> +<p><a href="https://colab.research.google.com/github/Nixtla/hierarchicalforecast/blob/main/nbs/examples/MLFrameworksExample.ipynb" target="_parent"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"></a></p> +<section id="installing-packages" class="level2"> +<h2 class="anchored" data-anchor-id="installing-packages">1. Installing packages</h2> +<div class="cell"> +<div class="sourceCode cell-code" id="cb1"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="op">!</span>pip install datasetsforecast mlforecast </span> +<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="op">!</span>pip install git<span class="op">+</span>https:<span class="op">//</span>github.com<span class="op">/</span>Nixtla<span class="op">/</span>neuralforecast.git</span> +<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="op">!</span>pip install git<span class="op">+</span>https:<span class="op">//</span>github.com<span class="op">/</span>Nixtla<span class="op">/</span>hierarchicalforecast.git</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb2"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> numpy <span class="im">as</span> np</span> +<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> pandas <span class="im">as</span> pd</span> +<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> datasetsforecast.hierarchical <span class="im">import</span> HierarchicalData</span> +<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> neuralforecast <span class="im">import</span> NeuralForecast</span> +<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> neuralforecast.models <span class="im">import</span> NBEATS</span> +<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> neuralforecast.losses.pytorch <span class="im">import</span> GMM</span> +<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> mlforecast <span class="im">import</span> MLForecast</span> +<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> window_ops.expanding <span class="im">import</span> expanding_mean</span> +<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> mlforecast.utils <span class="im">import</span> PredictionIntervals</span> +<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> mlforecast.target_transforms <span class="im">import</span> Differences</span> +<span id="cb2-14"><a href="#cb2-14" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> xgboost <span class="im">as</span> xgb</span> +<span id="cb2-15"><a href="#cb2-15" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb2-16"><a href="#cb2-16" aria-hidden="true" tabindex="-1"></a><span class="co">#obtain hierarchical reconciliation methods and evaluation</span></span> +<span id="cb2-17"><a href="#cb2-17" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> hierarchicalforecast.methods <span class="im">import</span> BottomUp, MinTrace</span> +<span id="cb2-18"><a href="#cb2-18" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> hierarchicalforecast.utils <span class="im">import</span> HierarchicalPlot</span> +<span id="cb2-19"><a href="#cb2-19" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> hierarchicalforecast.core <span class="im">import</span> HierarchicalReconciliation</span> +<span id="cb2-20"><a href="#cb2-20" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> hierarchicalforecast.evaluation <span class="im">import</span> scaled_crps</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +</section> +<section id="load-hierarchical-dataset" class="level2"> +<h2 class="anchored" data-anchor-id="load-hierarchical-dataset">2. Load hierarchical dataset</h2> +<p>This detailed Australian Tourism Dataset comes from the National Visitor Survey, managed by the Tourism Research Australia, it is composed of 555 monthly series from 1998 to 2016, it is organized geographically, and purpose of travel. The natural geographical hierarchy comprises seven states, divided further in 27 zones and 76 regions. The purpose of travel categories are holiday, visiting friends and relatives (VFR), business and other. The MinT (Wickramasuriya et al., 2019), among other hierarchical forecasting studies has used the dataset it in the past. The dataset can be accessed in the <a href="https://robjhyndman.com/publications/mint/">MinT reconciliation webpage</a>, although other sources are available.</p> +<table class="table"> +<colgroup> +<col style="width: 25%"> +<col style="width: 25%"> +<col style="width: 25%"> +<col style="width: 25%"> +</colgroup> +<thead> +<tr class="header"> +<th>Geographical Division</th> +<th>Number of series per division</th> +<th>Number of series per purpose</th> +<th>Total</th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td>Australia</td> +<td>1</td> +<td>4</td> +<td>5</td> +</tr> +<tr class="even"> +<td>States</td> +<td>7</td> +<td>28</td> +<td>35</td> +</tr> +<tr class="odd"> +<td>Zones</td> +<td>27</td> +<td>108</td> +<td>135</td> +</tr> +<tr class="even"> +<td>Regions</td> +<td>76</td> +<td>304</td> +<td>380</td> +</tr> +<tr class="odd"> +<td>Total</td> +<td>111</td> +<td>444</td> +<td>555</td> +</tr> +</tbody> +</table> +<div class="cell"> +<div class="sourceCode cell-code" id="cb3"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a>Y_df, S_df, tags <span class="op">=</span> HierarchicalData.load(<span class="st">'./data'</span>, <span class="st">'TourismLarge'</span>)</span> +<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>Y_df[<span class="st">'ds'</span>] <span class="op">=</span> pd.to_datetime(Y_df[<span class="st">'ds'</span>])</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb4"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a>Y_df.head()</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> + + <div id="df-45505ecd-2165-402b-831a-08c6d4be030d"> + <div class="colab-df-container"> + <div> + + +<table class="dataframe table table-sm table-striped small" data-quarto-postprocess="true" data-border="1"> +<thead> +<tr class="header"> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th">unique_id</th> +<th data-quarto-table-cell-role="th">ds</th> +<th data-quarto-table-cell-role="th">y</th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td data-quarto-table-cell-role="th">0</td> +<td>TotalAll</td> +<td>1998-01-01</td> +<td>45151.071280</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">1</td> +<td>TotalAll</td> +<td>1998-02-01</td> +<td>17294.699551</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">2</td> +<td>TotalAll</td> +<td>1998-03-01</td> +<td>20725.114184</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">3</td> +<td>TotalAll</td> +<td>1998-04-01</td> +<td>25388.612353</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">4</td> +<td>TotalAll</td> +<td>1998-05-01</td> +<td>20330.035211</td> +</tr> +</tbody> +</table> + + +</div> + <button class="colab-df-convert" onclick="convertToInteractive('df-45505ecd-2165-402b-831a-08c6d4be030d')" title="Convert this dataframe to an interactive table." style="display:none;"> + + <svg xmlns="http://www.w3.org/2000/svg" height="24px" viewbox="0 0 24 24" width="24px"> + <path d="M0 0h24v24H0V0z" fill="none"></path> + <path d="M18.56 5.44l.94 2.06.94-2.06 2.06-.94-2.06-.94-.94-2.06-.94 2.06-2.06.94zm-11 1L8.5 8.5l.94-2.06 2.06-.94-2.06-.94L8.5 2.5l-.94 2.06-2.06.94zm10 10l.94 2.06.94-2.06 2.06-.94-2.06-.94-.94-2.06-.94 2.06-2.06.94z"></path><path d="M17.41 7.96l-1.37-1.37c-.4-.4-.92-.59-1.43-.59-.52 0-1.04.2-1.43.59L10.3 9.45l-7.72 7.72c-.78.78-.78 2.05 0 2.83L4 21.41c.39.39.9.59 1.41.59.51 0 1.02-.2 1.41-.59l7.78-7.78 2.81-2.81c.8-.78.8-2.07 0-2.86zM5.41 20L4 18.59l7.72-7.72 1.47 1.35L5.41 20z"></path> + </svg> + </button> + + <style> + .colab-df-container { + display:flex; + flex-wrap:wrap; + gap: 12px; + } + + .colab-df-convert { + background-color: #E8F0FE; + border: none; + border-radius: 50%; + cursor: pointer; + display: none; + fill: #1967D2; + height: 32px; + padding: 0 0 0 0; + width: 32px; + } + + .colab-df-convert:hover { + background-color: #E2EBFA; + box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 1px 3px 1px rgba(60, 64, 67, 0.15); + fill: #174EA6; + } + + [theme=dark] .colab-df-convert { + background-color: #3B4455; + fill: #D2E3FC; + } + + [theme=dark] .colab-df-convert:hover { + background-color: #434B5C; + box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.15); + filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.3)); + fill: #FFFFFF; + } + </style> + + <script> + const buttonEl = + document.querySelector('#df-45505ecd-2165-402b-831a-08c6d4be030d button.colab-df-convert'); + buttonEl.style.display = + google.colab.kernel.accessAllowed ? 'block' : 'none'; + + async function convertToInteractive(key) { + const element = document.querySelector('#df-45505ecd-2165-402b-831a-08c6d4be030d'); + const dataTable = + await google.colab.kernel.invokeFunction('convertToInteractive', + [key], {}); + if (!dataTable) return; + + const docLinkHtml = 'Like what you see? Visit the ' + + '<a target="_blank" href=https://colab.research.google.com/notebooks/data_table.ipynb>data table notebook</a>' + + ' to learn more about interactive tables.'; + element.innerHTML = ''; + dataTable['output_type'] = 'display_data'; + await google.colab.output.renderOutput(dataTable, element); + const docLink = document.createElement('div'); + docLink.innerHTML = docLinkHtml; + element.appendChild(docLink); + } + </script> + </div> + </div> + +</div> +</div> +<p>Visualize the aggregation matrix.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb5"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a>hplot <span class="op">=</span> HierarchicalPlot(S<span class="op">=</span>S_df, tags<span class="op">=</span>tags)</span> +<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a>hplot.plot_summing_matrix()</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<p><img src="MLFrameworksExample_files/figure-html/cell-6-output-1.png" class="img-fluid"></p> +</div> +</div> +<p>Split the dataframe in train/test splits.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb6"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> sort_hier_df(Y_df, S_df):</span> +<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a> <span class="co"># sorts unique_id lexicographically</span></span> +<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a> Y_df.unique_id <span class="op">=</span> Y_df.unique_id.astype(<span class="st">'category'</span>)</span> +<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a> Y_df.unique_id <span class="op">=</span> Y_df.unique_id.cat.set_categories(S_df.index)</span> +<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a> Y_df <span class="op">=</span> Y_df.sort_values(by<span class="op">=</span>[<span class="st">'unique_id'</span>, <span class="st">'ds'</span>])</span> +<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> Y_df</span> +<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a>Y_df <span class="op">=</span> sort_hier_df(Y_df, S_df)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb7"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a>horizon <span class="op">=</span> <span class="dv">12</span></span> +<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a>Y_test_df <span class="op">=</span> Y_df.groupby(<span class="st">'unique_id'</span>).tail(horizon)</span> +<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a>Y_train_df <span class="op">=</span> Y_df.drop(Y_test_df.index)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +</section> +<section id="fit-and-predict-models" class="level2"> +<h2 class="anchored" data-anchor-id="fit-and-predict-models">3. Fit and Predict Models</h2> +<p>HierarchicalForecast is compatible with many different ML models. Here, we show two examples:<br> 1. NBEATS, a MLP-based deep neural architecture.<br> 2. XGBRegressor, a tree-based architecture.<br></p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb8"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a>level <span class="op">=</span> np.arange(<span class="dv">0</span>, <span class="dv">100</span>, <span class="dv">2</span>)</span> +<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a>qs <span class="op">=</span> [[<span class="dv">50</span><span class="op">-</span>lv<span class="op">/</span><span class="dv">2</span>, <span class="dv">50</span><span class="op">+</span>lv<span class="op">/</span><span class="dv">2</span>] <span class="cf">for</span> lv <span class="kw">in</span> level]</span> +<span id="cb8-3"><a href="#cb8-3" aria-hidden="true" tabindex="-1"></a>quantiles <span class="op">=</span> np.sort(np.concatenate(qs)<span class="op">/</span><span class="dv">100</span>)</span> +<span id="cb8-4"><a href="#cb8-4" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb8-5"><a href="#cb8-5" aria-hidden="true" tabindex="-1"></a><span class="co">#fit/predict NBEATS from NeuralForecast</span></span> +<span id="cb8-6"><a href="#cb8-6" aria-hidden="true" tabindex="-1"></a>nbeats <span class="op">=</span> NBEATS(h<span class="op">=</span>horizon,</span> +<span id="cb8-7"><a href="#cb8-7" aria-hidden="true" tabindex="-1"></a> input_size<span class="op">=</span><span class="dv">2</span><span class="op">*</span>horizon,</span> +<span id="cb8-8"><a href="#cb8-8" aria-hidden="true" tabindex="-1"></a> loss<span class="op">=</span>GMM(n_components<span class="op">=</span><span class="dv">10</span>, quantiles<span class="op">=</span>quantiles),</span> +<span id="cb8-9"><a href="#cb8-9" aria-hidden="true" tabindex="-1"></a> scaler_type<span class="op">=</span><span class="st">'robust'</span>,</span> +<span id="cb8-10"><a href="#cb8-10" aria-hidden="true" tabindex="-1"></a> max_steps<span class="op">=</span><span class="dv">2000</span>)</span> +<span id="cb8-11"><a href="#cb8-11" aria-hidden="true" tabindex="-1"></a>nf <span class="op">=</span> NeuralForecast(models<span class="op">=</span>[nbeats], freq<span class="op">=</span><span class="st">'MS'</span>)</span> +<span id="cb8-12"><a href="#cb8-12" aria-hidden="true" tabindex="-1"></a>nf.fit(df<span class="op">=</span>Y_train_df)</span> +<span id="cb8-13"><a href="#cb8-13" aria-hidden="true" tabindex="-1"></a>Y_hat_nf <span class="op">=</span> nf.predict()</span> +<span id="cb8-14"><a href="#cb8-14" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb8-15"><a href="#cb8-15" aria-hidden="true" tabindex="-1"></a><span class="co">#fit/predict XGBRegressor from MLForecast</span></span> +<span id="cb8-16"><a href="#cb8-16" aria-hidden="true" tabindex="-1"></a>mf <span class="op">=</span> MLForecast(models<span class="op">=</span>[xgb.XGBRegressor()], </span> +<span id="cb8-17"><a href="#cb8-17" aria-hidden="true" tabindex="-1"></a> freq<span class="op">=</span><span class="st">'MS'</span>,</span> +<span id="cb8-18"><a href="#cb8-18" aria-hidden="true" tabindex="-1"></a> lags<span class="op">=</span>[<span class="dv">1</span>,<span class="dv">2</span>,<span class="dv">12</span>,<span class="dv">24</span>],</span> +<span id="cb8-19"><a href="#cb8-19" aria-hidden="true" tabindex="-1"></a> date_features<span class="op">=</span>[<span class="st">'month'</span>],</span> +<span id="cb8-20"><a href="#cb8-20" aria-hidden="true" tabindex="-1"></a> )</span> +<span id="cb8-21"><a href="#cb8-21" aria-hidden="true" tabindex="-1"></a>mf.fit(Y_train_df, prediction_intervals<span class="op">=</span>PredictionIntervals(n_windows<span class="op">=</span><span class="dv">10</span>, window_size<span class="op">=</span>horizon)) </span> +<span id="cb8-22"><a href="#cb8-22" aria-hidden="true" tabindex="-1"></a>Y_hat_mf <span class="op">=</span> mf.predict(horizon, level<span class="op">=</span>level).set_index(<span class="st">'unique_id'</span>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-stderr"> +<pre><code>INFO:lightning_fabric.utilities.seed:Global seed set to 1</code></pre> +</div> +<div class="cell-output cell-output-display"> +<script type="application/vnd.jupyter.widget-view+json"> +{"model_id":"2c3850495c68413f9c60db92872398b5","version_major":2,"version_minor":0,"quarto_mimetype":"application/vnd.jupyter.widget-view+json"} +</script> +</div> +<div class="cell-output cell-output-display"> +<script type="application/vnd.jupyter.widget-view+json"> +{"model_id":"d9f8ee949dc847e68a057fb8a87eea7e","version_major":2,"version_minor":0,"quarto_mimetype":"application/vnd.jupyter.widget-view+json"} +</script> +</div> +<div class="cell-output cell-output-display"> +<script type="application/vnd.jupyter.widget-view+json"> +{"model_id":"30afe0b88221426780ec9570767d664c","version_major":2,"version_minor":0,"quarto_mimetype":"application/vnd.jupyter.widget-view+json"} +</script> +</div> +<div class="cell-output cell-output-display"> +<script type="application/vnd.jupyter.widget-view+json"> +{"model_id":"3eaf8d9c4d99437cadad546d34032899","version_major":2,"version_minor":0,"quarto_mimetype":"application/vnd.jupyter.widget-view+json"} +</script> +</div> +<div class="cell-output cell-output-display"> +<script type="application/vnd.jupyter.widget-view+json"> +{"model_id":"98a562b85c6a493eacdeb22154e3cea7","version_major":2,"version_minor":0,"quarto_mimetype":"application/vnd.jupyter.widget-view+json"} +</script> +</div> +<div class="cell-output cell-output-display"> +<script type="application/vnd.jupyter.widget-view+json"> +{"model_id":"f7351fa56f2f4a75b72b36f0295680d0","version_major":2,"version_minor":0,"quarto_mimetype":"application/vnd.jupyter.widget-view+json"} +</script> +</div> +<div class="cell-output cell-output-display"> +<script type="application/vnd.jupyter.widget-view+json"> +{"model_id":"d6c5cd33636a46e787508e55e12e5532","version_major":2,"version_minor":0,"quarto_mimetype":"application/vnd.jupyter.widget-view+json"} +</script> +</div> +<div class="cell-output cell-output-display"> +<script type="application/vnd.jupyter.widget-view+json"> +{"model_id":"7fc7b2f0dfc54cd3aa4272a9589b0187","version_major":2,"version_minor":0,"quarto_mimetype":"application/vnd.jupyter.widget-view+json"} +</script> +</div> +<div class="cell-output cell-output-display"> +<script type="application/vnd.jupyter.widget-view+json"> +{"model_id":"ba442028da3744a684637564164ff036","version_major":2,"version_minor":0,"quarto_mimetype":"application/vnd.jupyter.widget-view+json"} +</script> +</div> +<div class="cell-output cell-output-display"> +<script type="application/vnd.jupyter.widget-view+json"> +{"model_id":"8ada728011e948498997edf37d29369b","version_major":2,"version_minor":0,"quarto_mimetype":"application/vnd.jupyter.widget-view+json"} +</script> +</div> +<div class="cell-output cell-output-display"> +<script type="application/vnd.jupyter.widget-view+json"> +{"model_id":"fb5c206785454e0c855f4f9be9c02613","version_major":2,"version_minor":0,"quarto_mimetype":"application/vnd.jupyter.widget-view+json"} +</script> +</div> +<div class="cell-output cell-output-display"> +<script type="application/vnd.jupyter.widget-view+json"> +{"model_id":"439e7bbe5a3b42b8a7624e9ea1077d2b","version_major":2,"version_minor":0,"quarto_mimetype":"application/vnd.jupyter.widget-view+json"} +</script> +</div> +<div class="cell-output cell-output-display"> +<script type="application/vnd.jupyter.widget-view+json"> +{"model_id":"7ddb7981b4e940f8b52dfa65536b47ed","version_major":2,"version_minor":0,"quarto_mimetype":"application/vnd.jupyter.widget-view+json"} +</script> +</div> +<div class="cell-output cell-output-display"> +<script type="application/vnd.jupyter.widget-view+json"> +{"model_id":"0f7a9e1a55ca4562baaa9738c4112fb1","version_major":2,"version_minor":0,"quarto_mimetype":"application/vnd.jupyter.widget-view+json"} +</script> +</div> +<div class="cell-output cell-output-display"> +<script type="application/vnd.jupyter.widget-view+json"> +{"model_id":"28e11b013ee844b9b614f7c488a9b031","version_major":2,"version_minor":0,"quarto_mimetype":"application/vnd.jupyter.widget-view+json"} +</script> +</div> +<div class="cell-output cell-output-display"> +<script type="application/vnd.jupyter.widget-view+json"> +{"model_id":"758c15ec4cf1470ea2ee45068b47b66d","version_major":2,"version_minor":0,"quarto_mimetype":"application/vnd.jupyter.widget-view+json"} +</script> +</div> +<div class="cell-output cell-output-display"> +<script type="application/vnd.jupyter.widget-view+json"> +{"model_id":"66f1ebaa14bd4caca5ce8f2aedc0a757","version_major":2,"version_minor":0,"quarto_mimetype":"application/vnd.jupyter.widget-view+json"} +</script> +</div> +<div class="cell-output cell-output-display"> +<script type="application/vnd.jupyter.widget-view+json"> +{"model_id":"10a55103bba642b88790b50f38496c8f","version_major":2,"version_minor":0,"quarto_mimetype":"application/vnd.jupyter.widget-view+json"} +</script> +</div> +<div class="cell-output cell-output-display"> +<script type="application/vnd.jupyter.widget-view+json"> +{"model_id":"c2f8fd113fb54a8583d1355411bad615","version_major":2,"version_minor":0,"quarto_mimetype":"application/vnd.jupyter.widget-view+json"} +</script> +</div> +<div class="cell-output cell-output-display"> +<script type="application/vnd.jupyter.widget-view+json"> +{"model_id":"72bbc6aa8c45498784faa9dfc972e212","version_major":2,"version_minor":0,"quarto_mimetype":"application/vnd.jupyter.widget-view+json"} +</script> +</div> +<div class="cell-output cell-output-display"> +<script type="application/vnd.jupyter.widget-view+json"> +{"model_id":"ec2785af9d934235abdd9f2030180f71","version_major":2,"version_minor":0,"quarto_mimetype":"application/vnd.jupyter.widget-view+json"} +</script> +</div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb10"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a>Y_hat_nf</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> + + <div id="df-35918737-fc9f-4e58-91fd-591898088c33"> + <div class="colab-df-container"> + <div> + + +<table class="dataframe table table-sm table-striped small" data-quarto-postprocess="true" data-border="1"> +<thead> +<tr class="header"> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th">ds</th> +<th data-quarto-table-cell-role="th">NBEATS</th> +<th data-quarto-table-cell-role="th">NBEATS-lo-98.0</th> +<th data-quarto-table-cell-role="th">NBEATS-lo-96.0</th> +<th data-quarto-table-cell-role="th">NBEATS-lo-94.0</th> +<th data-quarto-table-cell-role="th">NBEATS-lo-92.0</th> +<th data-quarto-table-cell-role="th">NBEATS-lo-90.0</th> +<th data-quarto-table-cell-role="th">NBEATS-lo-88.0</th> +<th data-quarto-table-cell-role="th">NBEATS-lo-86.0</th> +<th data-quarto-table-cell-role="th">NBEATS-lo-84.0</th> +<th data-quarto-table-cell-role="th">...</th> +<th data-quarto-table-cell-role="th">NBEATS-hi-80.0</th> +<th data-quarto-table-cell-role="th">NBEATS-hi-82.0</th> +<th data-quarto-table-cell-role="th">NBEATS-hi-84.0</th> +<th data-quarto-table-cell-role="th">NBEATS-hi-86.0</th> +<th data-quarto-table-cell-role="th">NBEATS-hi-88.0</th> +<th data-quarto-table-cell-role="th">NBEATS-hi-90.0</th> +<th data-quarto-table-cell-role="th">NBEATS-hi-92.0</th> +<th data-quarto-table-cell-role="th">NBEATS-hi-94.0</th> +<th data-quarto-table-cell-role="th">NBEATS-hi-96.0</th> +<th data-quarto-table-cell-role="th">NBEATS-hi-98.0</th> +</tr> +<tr class="odd"> +<th data-quarto-table-cell-role="th">unique_id</th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td data-quarto-table-cell-role="th">TotalAll</td> +<td>2016-01-01</td> +<td>44304.039062</td> +<td>24825.771484</td> +<td>26974.607422</td> +<td>27405.914062</td> +<td>27881.269531</td> +<td>28640.238281</td> +<td>29469.513672</td> +<td>30213.277344</td> +<td>31009.929688</td> +<td>...</td> +<td>51838.828125</td> +<td>52150.523438</td> +<td>52404.886719</td> +<td>52564.652344</td> +<td>52951.238281</td> +<td>53216.839844</td> +<td>53689.351562</td> +<td>54015.074219</td> +<td>54545.882812</td> +<td>55752.621094</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">TotalAll</td> +<td>2016-02-01</td> +<td>20877.984375</td> +<td>17909.365234</td> +<td>18334.902344</td> +<td>18577.355469</td> +<td>18653.085938</td> +<td>18755.072266</td> +<td>18839.824219</td> +<td>18965.947266</td> +<td>19074.134766</td> +<td>...</td> +<td>22756.220703</td> +<td>22892.509766</td> +<td>23029.402344</td> +<td>23133.941406</td> +<td>23221.666016</td> +<td>23385.628906</td> +<td>23587.021484</td> +<td>23862.343750</td> +<td>24243.560547</td> +<td>24526.462891</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">TotalAll</td> +<td>2016-03-01</td> +<td>23444.972656</td> +<td>18971.355469</td> +<td>19329.705078</td> +<td>19472.619141</td> +<td>19756.503906</td> +<td>19843.703125</td> +<td>20075.363281</td> +<td>20126.689453</td> +<td>20259.271484</td> +<td>...</td> +<td>26024.242188</td> +<td>26116.677734</td> +<td>26196.498047</td> +<td>26342.339844</td> +<td>26535.798828</td> +<td>26758.476562</td> +<td>26934.582031</td> +<td>27097.130859</td> +<td>27441.996094</td> +<td>27704.375000</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">TotalAll</td> +<td>2016-04-01</td> +<td>28927.132812</td> +<td>24030.257812</td> +<td>24540.779297</td> +<td>24732.566406</td> +<td>24988.001953</td> +<td>25160.744141</td> +<td>25304.658203</td> +<td>25456.001953</td> +<td>25567.078125</td> +<td>...</td> +<td>31568.966797</td> +<td>31698.855469</td> +<td>31856.851562</td> +<td>32097.916016</td> +<td>32211.320312</td> +<td>32345.988281</td> +<td>32510.902344</td> +<td>32724.638672</td> +<td>33078.031250</td> +<td>33525.035156</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">TotalAll</td> +<td>2016-05-01</td> +<td>22716.433594</td> +<td>19728.511719</td> +<td>19910.925781</td> +<td>20089.443359</td> +<td>20214.955078</td> +<td>20269.906250</td> +<td>20355.708984</td> +<td>20441.349609</td> +<td>20491.029297</td> +<td>...</td> +<td>24937.335938</td> +<td>25114.396484</td> +<td>25270.279297</td> +<td>25446.765625</td> +<td>25676.287109</td> +<td>26028.427734</td> +<td>26440.011719</td> +<td>27477.541016</td> +<td>28452.419922</td> +<td>29793.591797</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">GBDOth</td> +<td>2016-08-01</td> +<td>4.731373</td> +<td>-30.691290</td> +<td>-8.694043</td> +<td>-2.576124</td> +<td>-2.196553</td> +<td>-2.069076</td> +<td>-1.913422</td> +<td>-1.854156</td> +<td>-1.767804</td> +<td>...</td> +<td>9.252028</td> +<td>10.948211</td> +<td>12.031944</td> +<td>14.396760</td> +<td>18.523523</td> +<td>43.287716</td> +<td>58.207531</td> +<td>69.754929</td> +<td>81.399673</td> +<td>116.701561</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">GBDOth</td> +<td>2016-09-01</td> +<td>5.685491</td> +<td>-32.813366</td> +<td>-11.985416</td> +<td>-2.978264</td> +<td>-2.413029</td> +<td>-2.120405</td> +<td>-1.788605</td> +<td>-1.673310</td> +<td>-1.550562</td> +<td>...</td> +<td>12.787840</td> +<td>14.330542</td> +<td>15.563581</td> +<td>16.996040</td> +<td>29.901039</td> +<td>45.086597</td> +<td>60.724380</td> +<td>75.462578</td> +<td>92.432518</td> +<td>125.217796</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">GBDOth</td> +<td>2016-10-01</td> +<td>4.760162</td> +<td>-51.105358</td> +<td>-27.034277</td> +<td>-8.493114</td> +<td>-2.859874</td> +<td>-2.140030</td> +<td>-1.905673</td> +<td>-1.764797</td> +<td>-1.621011</td> +<td>...</td> +<td>10.930604</td> +<td>11.960605</td> +<td>13.876516</td> +<td>14.839364</td> +<td>18.540100</td> +<td>32.251144</td> +<td>48.573261</td> +<td>65.301460</td> +<td>83.327026</td> +<td>113.249001</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">GBDOth</td> +<td>2016-11-01</td> +<td>6.491304</td> +<td>-31.302568</td> +<td>-6.776994</td> +<td>-2.816422</td> +<td>-2.196187</td> +<td>-2.002094</td> +<td>-1.806302</td> +<td>-1.613474</td> +<td>-1.538146</td> +<td>...</td> +<td>14.449442</td> +<td>15.161877</td> +<td>17.715519</td> +<td>22.247185</td> +<td>39.648643</td> +<td>52.634579</td> +<td>67.812111</td> +<td>75.647865</td> +<td>85.764038</td> +<td>116.143196</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">GBDOth</td> +<td>2016-12-01</td> +<td>6.683663</td> +<td>-37.663929</td> +<td>-13.461041</td> +<td>-2.384047</td> +<td>-2.037058</td> +<td>-1.877487</td> +<td>-1.620457</td> +<td>-1.436237</td> +<td>-1.304141</td> +<td>...</td> +<td>15.086438</td> +<td>16.038090</td> +<td>18.206852</td> +<td>24.431122</td> +<td>35.078407</td> +<td>44.138805</td> +<td>62.435913</td> +<td>77.259911</td> +<td>104.585594</td> +<td>123.915787</td> +</tr> +</tbody> +</table> + + +<p>6660 rows Ć 102 columns</p> +</div> + <button class="colab-df-convert" onclick="convertToInteractive('df-35918737-fc9f-4e58-91fd-591898088c33')" title="Convert this dataframe to an interactive table." style="display:none;"> + + <svg xmlns="http://www.w3.org/2000/svg" height="24px" viewbox="0 0 24 24" width="24px"> + <path d="M0 0h24v24H0V0z" fill="none"></path> + <path d="M18.56 5.44l.94 2.06.94-2.06 2.06-.94-2.06-.94-.94-2.06-.94 2.06-2.06.94zm-11 1L8.5 8.5l.94-2.06 2.06-.94-2.06-.94L8.5 2.5l-.94 2.06-2.06.94zm10 10l.94 2.06.94-2.06 2.06-.94-2.06-.94-.94-2.06-.94 2.06-2.06.94z"></path><path d="M17.41 7.96l-1.37-1.37c-.4-.4-.92-.59-1.43-.59-.52 0-1.04.2-1.43.59L10.3 9.45l-7.72 7.72c-.78.78-.78 2.05 0 2.83L4 21.41c.39.39.9.59 1.41.59.51 0 1.02-.2 1.41-.59l7.78-7.78 2.81-2.81c.8-.78.8-2.07 0-2.86zM5.41 20L4 18.59l7.72-7.72 1.47 1.35L5.41 20z"></path> + </svg> + </button> + + <style> + .colab-df-container { + display:flex; + flex-wrap:wrap; + gap: 12px; + } + + .colab-df-convert { + background-color: #E8F0FE; + border: none; + border-radius: 50%; + cursor: pointer; + display: none; + fill: #1967D2; + height: 32px; + padding: 0 0 0 0; + width: 32px; + } + + .colab-df-convert:hover { + background-color: #E2EBFA; + box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 1px 3px 1px rgba(60, 64, 67, 0.15); + fill: #174EA6; + } + + [theme=dark] .colab-df-convert { + background-color: #3B4455; + fill: #D2E3FC; + } + + [theme=dark] .colab-df-convert:hover { + background-color: #434B5C; + box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.15); + filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.3)); + fill: #FFFFFF; + } + </style> + + <script> + const buttonEl = + document.querySelector('#df-35918737-fc9f-4e58-91fd-591898088c33 button.colab-df-convert'); + buttonEl.style.display = + google.colab.kernel.accessAllowed ? 'block' : 'none'; + + async function convertToInteractive(key) { + const element = document.querySelector('#df-35918737-fc9f-4e58-91fd-591898088c33'); + const dataTable = + await google.colab.kernel.invokeFunction('convertToInteractive', + [key], {}); + if (!dataTable) return; + + const docLinkHtml = 'Like what you see? Visit the ' + + '<a target="_blank" href=https://colab.research.google.com/notebooks/data_table.ipynb>data table notebook</a>' + + ' to learn more about interactive tables.'; + element.innerHTML = ''; + dataTable['output_type'] = 'display_data'; + await google.colab.output.renderOutput(dataTable, element); + const docLink = document.createElement('div'); + docLink.innerHTML = docLinkHtml; + element.appendChild(docLink); + } + </script> + </div> + </div> + +</div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb11"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a>Y_hat_mf</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> + + <div id="df-31fcbbd1-1694-4441-82eb-4dfc73833a1f"> + <div class="colab-df-container"> + <div> + + +<table class="dataframe table table-sm table-striped small" data-quarto-postprocess="true" data-border="1"> +<thead> +<tr class="header"> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th">ds</th> +<th data-quarto-table-cell-role="th">XGBRegressor</th> +<th data-quarto-table-cell-role="th">XGBRegressor-lo-98</th> +<th data-quarto-table-cell-role="th">XGBRegressor-lo-96</th> +<th data-quarto-table-cell-role="th">XGBRegressor-lo-94</th> +<th data-quarto-table-cell-role="th">XGBRegressor-lo-92</th> +<th data-quarto-table-cell-role="th">XGBRegressor-lo-90</th> +<th data-quarto-table-cell-role="th">XGBRegressor-lo-88</th> +<th data-quarto-table-cell-role="th">XGBRegressor-lo-86</th> +<th data-quarto-table-cell-role="th">XGBRegressor-lo-84</th> +<th data-quarto-table-cell-role="th">...</th> +<th data-quarto-table-cell-role="th">XGBRegressor-hi-80</th> +<th data-quarto-table-cell-role="th">XGBRegressor-hi-82</th> +<th data-quarto-table-cell-role="th">XGBRegressor-hi-84</th> +<th data-quarto-table-cell-role="th">XGBRegressor-hi-86</th> +<th data-quarto-table-cell-role="th">XGBRegressor-hi-88</th> +<th data-quarto-table-cell-role="th">XGBRegressor-hi-90</th> +<th data-quarto-table-cell-role="th">XGBRegressor-hi-92</th> +<th data-quarto-table-cell-role="th">XGBRegressor-hi-94</th> +<th data-quarto-table-cell-role="th">XGBRegressor-hi-96</th> +<th data-quarto-table-cell-role="th">XGBRegressor-hi-98</th> +</tr> +<tr class="odd"> +<th data-quarto-table-cell-role="th">unique_id</th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td data-quarto-table-cell-role="th">TotalAll</td> +<td>2016-01-01</td> +<td>43891.531250</td> +<td>39048.053886</td> +<td>39398.911368</td> +<td>39749.768850</td> +<td>40100.626332</td> +<td>40451.483815</td> +<td>40561.804681</td> +<td>40586.219613</td> +<td>40610.634545</td> +<td>...</td> +<td>47123.598090</td> +<td>47148.013022</td> +<td>47172.427955</td> +<td>47196.842887</td> +<td>47221.257819</td> +<td>47331.578685</td> +<td>47682.436168</td> +<td>48033.293650</td> +<td>48384.151132</td> +<td>48735.008614</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">TotalAll</td> +<td>2016-02-01</td> +<td>20715.656250</td> +<td>18476.756884</td> +<td>18482.492537</td> +<td>18488.228190</td> +<td>18493.963842</td> +<td>18499.699495</td> +<td>18539.212692</td> +<td>18590.789297</td> +<td>18642.365902</td> +<td>...</td> +<td>22685.793388</td> +<td>22737.369993</td> +<td>22788.946598</td> +<td>22840.523203</td> +<td>22892.099808</td> +<td>22931.613005</td> +<td>22937.348658</td> +<td>22943.084310</td> +<td>22948.819963</td> +<td>22954.555616</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">TotalAll</td> +<td>2016-03-01</td> +<td>23008.896484</td> +<td>17292.312227</td> +<td>17323.859641</td> +<td>17355.407055</td> +<td>17386.954469</td> +<td>17418.501883</td> +<td>17582.396869</td> +<td>17793.558844</td> +<td>18004.720819</td> +<td>...</td> +<td>27590.748200</td> +<td>27801.910175</td> +<td>28013.072150</td> +<td>28224.234125</td> +<td>28435.396100</td> +<td>28599.291085</td> +<td>28630.838500</td> +<td>28662.385914</td> +<td>28693.933328</td> +<td>28725.480742</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">TotalAll</td> +<td>2016-04-01</td> +<td>27731.050781</td> +<td>22333.047144</td> +<td>22537.510145</td> +<td>22741.973145</td> +<td>22946.436145</td> +<td>23150.899146</td> +<td>23233.881164</td> +<td>23273.477118</td> +<td>23313.073071</td> +<td>...</td> +<td>32069.836584</td> +<td>32109.432538</td> +<td>32149.028491</td> +<td>32188.624445</td> +<td>32228.220398</td> +<td>32311.202417</td> +<td>32515.665417</td> +<td>32720.128417</td> +<td>32924.591418</td> +<td>33129.054418</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">TotalAll</td> +<td>2016-05-01</td> +<td>24898.529297</td> +<td>21768.004677</td> +<td>21859.564615</td> +<td>21951.124552</td> +<td>22042.684490</td> +<td>22134.244428</td> +<td>22222.835407</td> +<td>22310.366042</td> +<td>22397.896678</td> +<td>...</td> +<td>27224.100644</td> +<td>27311.631280</td> +<td>27399.161916</td> +<td>27486.692551</td> +<td>27574.223187</td> +<td>27662.814166</td> +<td>27754.374104</td> +<td>27845.934041</td> +<td>27937.493979</td> +<td>28029.053917</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">GBDOth</td> +<td>2016-08-01</td> +<td>8.842277</td> +<td>-2.504086</td> +<td>-1.296329</td> +<td>-0.088571</td> +<td>1.119187</td> +<td>2.326944</td> +<td>2.794274</td> +<td>2.997165</td> +<td>3.200056</td> +<td>...</td> +<td>14.078715</td> +<td>14.281606</td> +<td>14.484497</td> +<td>14.687388</td> +<td>14.890279</td> +<td>15.357609</td> +<td>16.565366</td> +<td>17.773124</td> +<td>18.980882</td> +<td>20.188639</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">GBDOth</td> +<td>2016-09-01</td> +<td>4.991811</td> +<td>-1.879816</td> +<td>-1.879816</td> +<td>-1.879816</td> +<td>-1.879816</td> +<td>-1.879816</td> +<td>-1.635940</td> +<td>-1.304965</td> +<td>-0.973990</td> +<td>...</td> +<td>10.295662</td> +<td>10.626637</td> +<td>10.957612</td> +<td>11.288587</td> +<td>11.619561</td> +<td>11.863438</td> +<td>11.863438</td> +<td>11.863438</td> +<td>11.863438</td> +<td>11.863438</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">GBDOth</td> +<td>2016-10-01</td> +<td>8.647715</td> +<td>2.339581</td> +<td>2.339581</td> +<td>2.339581</td> +<td>2.339581</td> +<td>2.339581</td> +<td>2.339581</td> +<td>2.339581</td> +<td>2.339581</td> +<td>...</td> +<td>14.955848</td> +<td>14.955848</td> +<td>14.955848</td> +<td>14.955848</td> +<td>14.955848</td> +<td>14.955848</td> +<td>14.955848</td> +<td>14.955848</td> +<td>14.955848</td> +<td>14.955848</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">GBDOth</td> +<td>2016-11-01</td> +<td>5.180346</td> +<td>0.451095</td> +<td>0.451095</td> +<td>0.451095</td> +<td>0.451095</td> +<td>0.451095</td> +<td>0.451095</td> +<td>0.451095</td> +<td>0.451095</td> +<td>...</td> +<td>9.909597</td> +<td>9.909597</td> +<td>9.909597</td> +<td>9.909597</td> +<td>9.909597</td> +<td>9.909597</td> +<td>9.909597</td> +<td>9.909597</td> +<td>9.909597</td> +<td>9.909597</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">GBDOth</td> +<td>2016-12-01</td> +<td>6.052622</td> +<td>1.791351</td> +<td>1.791351</td> +<td>1.791351</td> +<td>1.791351</td> +<td>1.791351</td> +<td>1.791351</td> +<td>1.791351</td> +<td>1.791351</td> +<td>...</td> +<td>10.313892</td> +<td>10.313892</td> +<td>10.313892</td> +<td>10.313892</td> +<td>10.313892</td> +<td>10.313892</td> +<td>10.313892</td> +<td>10.313892</td> +<td>10.313892</td> +<td>10.313892</td> +</tr> +</tbody> +</table> + + +<p>6660 rows Ć 102 columns</p> +</div> + <button class="colab-df-convert" onclick="convertToInteractive('df-31fcbbd1-1694-4441-82eb-4dfc73833a1f')" title="Convert this dataframe to an interactive table." style="display:none;"> + + <svg xmlns="http://www.w3.org/2000/svg" height="24px" viewbox="0 0 24 24" width="24px"> + <path d="M0 0h24v24H0V0z" fill="none"></path> + <path d="M18.56 5.44l.94 2.06.94-2.06 2.06-.94-2.06-.94-.94-2.06-.94 2.06-2.06.94zm-11 1L8.5 8.5l.94-2.06 2.06-.94-2.06-.94L8.5 2.5l-.94 2.06-2.06.94zm10 10l.94 2.06.94-2.06 2.06-.94-2.06-.94-.94-2.06-.94 2.06-2.06.94z"></path><path d="M17.41 7.96l-1.37-1.37c-.4-.4-.92-.59-1.43-.59-.52 0-1.04.2-1.43.59L10.3 9.45l-7.72 7.72c-.78.78-.78 2.05 0 2.83L4 21.41c.39.39.9.59 1.41.59.51 0 1.02-.2 1.41-.59l7.78-7.78 2.81-2.81c.8-.78.8-2.07 0-2.86zM5.41 20L4 18.59l7.72-7.72 1.47 1.35L5.41 20z"></path> + </svg> + </button> + + <style> + .colab-df-container { + display:flex; + flex-wrap:wrap; + gap: 12px; + } + + .colab-df-convert { + background-color: #E8F0FE; + border: none; + border-radius: 50%; + cursor: pointer; + display: none; + fill: #1967D2; + height: 32px; + padding: 0 0 0 0; + width: 32px; + } + + .colab-df-convert:hover { + background-color: #E2EBFA; + box-shadow: 0px 1px 2px rgba(60, 64, 67, 0.3), 0px 1px 3px 1px rgba(60, 64, 67, 0.15); + fill: #174EA6; + } + + [theme=dark] .colab-df-convert { + background-color: #3B4455; + fill: #D2E3FC; + } + + [theme=dark] .colab-df-convert:hover { + background-color: #434B5C; + box-shadow: 0px 1px 3px 1px rgba(0, 0, 0, 0.15); + filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, 0.3)); + fill: #FFFFFF; + } + </style> + + <script> + const buttonEl = + document.querySelector('#df-31fcbbd1-1694-4441-82eb-4dfc73833a1f button.colab-df-convert'); + buttonEl.style.display = + google.colab.kernel.accessAllowed ? 'block' : 'none'; + + async function convertToInteractive(key) { + const element = document.querySelector('#df-31fcbbd1-1694-4441-82eb-4dfc73833a1f'); + const dataTable = + await google.colab.kernel.invokeFunction('convertToInteractive', + [key], {}); + if (!dataTable) return; + + const docLinkHtml = 'Like what you see? Visit the ' + + '<a target="_blank" href=https://colab.research.google.com/notebooks/data_table.ipynb>data table notebook</a>' + + ' to learn more about interactive tables.'; + element.innerHTML = ''; + dataTable['output_type'] = 'display_data'; + await google.colab.output.renderOutput(dataTable, element); + const docLink = document.createElement('div'); + docLink.innerHTML = docLinkHtml; + element.appendChild(docLink); + } + </script> + </div> + </div> + +</div> +</div> +</section> +<section id="reconcile-predictions" class="level2"> +<h2 class="anchored" data-anchor-id="reconcile-predictions">4. Reconcile Predictions</h2> +<p>With minimal parsing, we can reconcile the raw output predictions with different HierarchicalForecast reconciliation methods.</p> +<div class="callout callout-style-default callout-warning callout-titled"> +<div class="callout-header d-flex align-content-center" data-bs-toggle="collapse" data-bs-target=".callout-1-contents" aria-controls="callout-1" aria-expanded="true" aria-label="Toggle callout"> +<div class="callout-icon-container"> +<i class="callout-icon"></i> +</div> +<div class="callout-title-container flex-fill"> +Reconciliation Methods Availability +</div> +<div class="callout-btn-toggle d-inline-block border-0 py-1 ps-1 pe-0 float-end"><i class="callout-toggle"></i></div> +</div> +<div id="callout-1" class="callout-1-contents callout-collapse collapse show"> +<div class="callout-body-container callout-body"> +<p>The following reconciliation methods require access to insample predictions:<br> - <code>ERM(method='closed'), ERM(method='reg_bu')</code><br> - <code>TopDown(method='average_proportions'), TopDown(method='proportion_averages')</code><br> - <code>MiddleOut(top_down_method='average_proportions'), MiddleOut(top_down_method='proportion_averages')</code><br> - <code>MinTrace(method='wls_var'), MinTrace(method='mint_cov'), MinTrace(method='mint_shrink')</code><br></p> +<p>You can obtain NeuralForecastās insample predictions via the <a href="https://nixtla.github.io/neuralforecast/core.html#neuralforecast.predict_insample"><code>NeuralForecast.predict_insample</code></a> method.</p> +<p>We are working on making MLForecastās insample predictions available.</p> +</div> +</div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb12"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a>reconcilers <span class="op">=</span> [</span> +<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a> BottomUp(),</span> +<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a> MinTrace(<span class="st">'ols'</span>)</span> +<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a>]</span> +<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a>hrec <span class="op">=</span> HierarchicalReconciliation(reconcilers<span class="op">=</span>reconcilers)</span> +<span id="cb12-6"><a href="#cb12-6" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb12-7"><a href="#cb12-7" aria-hidden="true" tabindex="-1"></a>Y_rec_nf <span class="op">=</span> hrec.reconcile(Y_hat_df<span class="op">=</span>Y_hat_nf, Y_df <span class="op">=</span> Y_train_df, S<span class="op">=</span>S_df, tags<span class="op">=</span>tags, level<span class="op">=</span>level)</span> +<span id="cb12-8"><a href="#cb12-8" aria-hidden="true" tabindex="-1"></a>Y_rec_mf <span class="op">=</span> hrec.reconcile(Y_hat_df<span class="op">=</span>Y_hat_mf, Y_df <span class="op">=</span> Y_train_df, S<span class="op">=</span>S_df, tags<span class="op">=</span>tags, level<span class="op">=</span>level)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +</section> +<section id="evaluation" class="level2"> +<h2 class="anchored" data-anchor-id="evaluation">5. Evaluation</h2> +<p>To evaluate we use a scaled variation of the CRPS, as proposed by Rangapuram (2021), to measure the accuracy of predicted quantiles <code>y_hat</code> compared to the observation <code>y</code>.</p> +<p><span class="math display">\[ \mathrm{sCRPS}(\hat{F}_{\tau}, \mathbf{y}_{\tau}) = \frac{2}{N} \sum_{i} +\int^{1}_{0} +\frac{\mathrm{QL}(\hat{F}_{i,\tau}, y_{i,\tau})_{q}}{\sum_{i} | y_{i,\tau} |} dq \]</span></p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb13"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a>rec_model_names_nf <span class="op">=</span> [<span class="st">'NBEATS/BottomUp'</span>, <span class="st">'NBEATS/MinTrace_method-ols'</span>]</span> +<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a>rec_model_names_mf <span class="op">=</span> [<span class="st">'XGBRegressor/BottomUp'</span>, <span class="st">'XGBRegressor/MinTrace_method-ols'</span>]</span> +<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a>n_quantiles <span class="op">=</span> <span class="bu">len</span>(quantiles)</span> +<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a>n_series <span class="op">=</span> <span class="bu">len</span>(S_df)</span> +<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> name <span class="kw">in</span> rec_model_names_nf:</span> +<span id="cb13-8"><a href="#cb13-8" aria-hidden="true" tabindex="-1"></a> quantile_columns <span class="op">=</span> [col <span class="cf">for</span> col <span class="kw">in</span> Y_rec_nf.columns <span class="cf">if</span> (name<span class="op">+</span><span class="st">'-lo'</span>) <span class="kw">in</span> col <span class="kw">or</span> (name<span class="op">+</span><span class="st">'-hi'</span>) <span class="kw">in</span> col]</span> +<span id="cb13-9"><a href="#cb13-9" aria-hidden="true" tabindex="-1"></a> y_rec <span class="op">=</span> Y_rec_nf[quantile_columns].values </span> +<span id="cb13-10"><a href="#cb13-10" aria-hidden="true" tabindex="-1"></a> y_test <span class="op">=</span> Y_test_df[<span class="st">'y'</span>].values</span> +<span id="cb13-11"><a href="#cb13-11" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb13-12"><a href="#cb13-12" aria-hidden="true" tabindex="-1"></a> y_rec <span class="op">=</span> y_rec.reshape(n_series, horizon, n_quantiles)</span> +<span id="cb13-13"><a href="#cb13-13" aria-hidden="true" tabindex="-1"></a> y_test <span class="op">=</span> y_test.reshape(n_series, horizon)</span> +<span id="cb13-14"><a href="#cb13-14" aria-hidden="true" tabindex="-1"></a> scrps <span class="op">=</span> scaled_crps(y<span class="op">=</span>y_test, y_hat<span class="op">=</span>y_rec, quantiles<span class="op">=</span>quantiles)</span> +<span id="cb13-15"><a href="#cb13-15" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"</span><span class="sc">{:<40}</span><span class="st"> </span><span class="sc">{:.5f}</span><span class="st">"</span>.<span class="bu">format</span>(name<span class="op">+</span><span class="st">":"</span>, scrps))</span> +<span id="cb13-16"><a href="#cb13-16" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb13-17"><a href="#cb13-17" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> name <span class="kw">in</span> rec_model_names_mf:</span> +<span id="cb13-18"><a href="#cb13-18" aria-hidden="true" tabindex="-1"></a> quantile_columns <span class="op">=</span> [col <span class="cf">for</span> col <span class="kw">in</span> Y_rec_mf.columns <span class="cf">if</span> (name<span class="op">+</span><span class="st">'-lo'</span>) <span class="kw">in</span> col <span class="kw">or</span> (name<span class="op">+</span><span class="st">'-hi'</span>) <span class="kw">in</span> col]</span> +<span id="cb13-19"><a href="#cb13-19" aria-hidden="true" tabindex="-1"></a> y_rec <span class="op">=</span> Y_rec_mf[quantile_columns].values </span> +<span id="cb13-20"><a href="#cb13-20" aria-hidden="true" tabindex="-1"></a> y_test <span class="op">=</span> Y_test_df[<span class="st">'y'</span>].values</span> +<span id="cb13-21"><a href="#cb13-21" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb13-22"><a href="#cb13-22" aria-hidden="true" tabindex="-1"></a> y_rec <span class="op">=</span> y_rec.reshape(n_series, horizon, n_quantiles)</span> +<span id="cb13-23"><a href="#cb13-23" aria-hidden="true" tabindex="-1"></a> y_test <span class="op">=</span> y_test.reshape(n_series, horizon)</span> +<span id="cb13-24"><a href="#cb13-24" aria-hidden="true" tabindex="-1"></a> scrps <span class="op">=</span> scaled_crps(y<span class="op">=</span>y_test, y_hat<span class="op">=</span>y_rec, quantiles<span class="op">=</span>quantiles)</span> +<span id="cb13-25"><a href="#cb13-25" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="st">"</span><span class="sc">{:<40}</span><span class="st"> </span><span class="sc">{:.5f}</span><span class="st">"</span>.<span class="bu">format</span>(name<span class="op">+</span><span class="st">":"</span>, scrps))</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-stdout"> +<pre><code>NBEATS/BottomUp: 0.12853 +NBEATS/MinTrace_method-ols: 0.12945 +XGBRegressor/BottomUp: 0.13202 +XGBRegressor/MinTrace_method-ols: 0.13417</code></pre> +</div> +</div> +</section> +<section id="visualizations" class="level2"> +<h2 class="anchored" data-anchor-id="visualizations">6. Visualizations</h2> +<div class="cell"> +<div class="sourceCode cell-code" id="cb15"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a>plot_nf <span class="op">=</span> pd.concat([Y_df.set_index([<span class="st">'unique_id'</span>, <span class="st">'ds'</span>]), </span> +<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a> Y_rec_nf.set_index(<span class="st">'ds'</span>, append<span class="op">=</span><span class="va">True</span>)], axis<span class="op">=</span><span class="dv">1</span>)</span> +<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a>plot_nf <span class="op">=</span> plot_nf.reset_index(<span class="st">'ds'</span>)</span> +<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb15-5"><a href="#cb15-5" aria-hidden="true" tabindex="-1"></a>plot_mf <span class="op">=</span> pd.concat([Y_df.set_index([<span class="st">'unique_id'</span>, <span class="st">'ds'</span>]), </span> +<span id="cb15-6"><a href="#cb15-6" aria-hidden="true" tabindex="-1"></a> Y_rec_mf.set_index(<span class="st">'ds'</span>, append<span class="op">=</span><span class="va">True</span>)], axis<span class="op">=</span><span class="dv">1</span>)</span> +<span id="cb15-7"><a href="#cb15-7" aria-hidden="true" tabindex="-1"></a>plot_mf <span class="op">=</span> plot_mf.reset_index(<span class="st">'ds'</span>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb16"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a>hplot.plot_series(</span> +<span id="cb16-2"><a href="#cb16-2" aria-hidden="true" tabindex="-1"></a> series<span class="op">=</span><span class="st">'TotalVis'</span>,</span> +<span id="cb16-3"><a href="#cb16-3" aria-hidden="true" tabindex="-1"></a> Y_df<span class="op">=</span>plot_nf, </span> +<span id="cb16-4"><a href="#cb16-4" aria-hidden="true" tabindex="-1"></a> models<span class="op">=</span>[<span class="st">'y'</span>, <span class="st">'NBEATS'</span>, <span class="st">'NBEATS/BottomUp'</span>, <span class="st">'NBEATS/MinTrace_method-ols'</span>],</span> +<span id="cb16-5"><a href="#cb16-5" aria-hidden="true" tabindex="-1"></a> level<span class="op">=</span>[<span class="dv">80</span>]</span> +<span id="cb16-6"><a href="#cb16-6" aria-hidden="true" tabindex="-1"></a>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<p><img src="MLFrameworksExample_files/figure-html/cell-15-output-1.png" class="img-fluid"></p> +</div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb17"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a>hplot.plot_series(</span> +<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a> series<span class="op">=</span><span class="st">'TotalVis'</span>,</span> +<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a> Y_df<span class="op">=</span>plot_mf, </span> +<span id="cb17-4"><a href="#cb17-4" aria-hidden="true" tabindex="-1"></a> models<span class="op">=</span>[<span class="st">'y'</span>, <span class="st">'XGBRegressor'</span>, <span class="st">'XGBRegressor/BottomUp'</span>, <span class="st">'XGBRegressor/MinTrace_method-ols'</span>],</span> +<span id="cb17-5"><a href="#cb17-5" aria-hidden="true" tabindex="-1"></a> level<span class="op">=</span>[<span class="dv">80</span>]</span> +<span id="cb17-6"><a href="#cb17-6" aria-hidden="true" tabindex="-1"></a>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<p><img src="MLFrameworksExample_files/figure-html/cell-16-output-1.png" class="img-fluid"></p> +</div> +</div> + + +</section> + +<p>If you find the code useful, please ā us on <a href="https://github.com/nixtla/hierarchicalforecast">Github</a></p></main> <!-- /main --> +<script type="application/vnd.jupyter.widget-state+json"> +{"0026a4e66ad64192a2474f8b175ecab6":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"019f47d763dc413ba614d6cfdf341baa":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_a341fb6e5ecf488b955c23ab4d9f9779","placeholder":"ā","style":"IPY_MODEL_9466f6af10b84050a489b53e4d89deac","value":" 18/18 [00:00<00:00, 248.62it/s]"}},"02832a8053b9468ba1527155e9b2889c":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"05b6d67cd4ba4f5ebf0ed9fbf769622b":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_b694b3ab3cf14361a5c3291878686a48","placeholder":"ā","style":"IPY_MODEL_5b50ca51622242da829dacc9a1ee2316","value":" 18/18 [00:00<00:00, 160.21it/s]"}},"060f7364f1ff4278916d38a14f713158":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"0856b7582be344babcc73be8eed57297":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_abb97079bd394f20975ea9c8bc3b45b4","placeholder":"ā","style":"IPY_MODEL_c5b32f0d793e457fa04a57126d9c6120","value":" 18/18 [00:00<00:00, 376.26it/s]"}},"08c631bc03574fe99133eb7d69c75bff":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_17e785d1e24545158d07969460ea99ed","placeholder":"ā","style":"IPY_MODEL_96baba250a4a498fa028a326e0f9df73","value":" 18/18 [00:00<00:00, 378.37it/s]"}},"0ae0f77a8393470c91307205b464e940":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_e6cbd39b82bb45a0a970885f687e12c5","placeholder":"ā","style":"IPY_MODEL_e74d8f4ad9944ff8bad0ceb755c6e70f","value":"Validation DataLoader 0: 100%"}},"0b3093c72da94fee93073cbdcd42da04":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"0b82189daceb4258a42021ba78690ea9":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":"inline-flex","flex":null,"flex_flow":"row wrap","grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":"hidden","width":"100%"}},"0ceda6ced454421bbccf50c82eb4188e":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"0d4f9f833c754a0dac509b43447e2944":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"0d6cea63e319436ba5ffe35fac7b48cd":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"","description":"","description_tooltip":null,"layout":"IPY_MODEL_7d5b27baa1ef4a8abf67bf06efcbe469","max":18,"min":0,"orientation":"horizontal","style":"IPY_MODEL_abc026faa7844ac4b506020f1590aba1","value":18}},"0de07aebf5454c9fbdc07f3ec49ce2b4":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"0f7a9e1a55ca4562baaa9738c4112fb1":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_2e47e76defa64ad29a4a64fae33ea4fb","IPY_MODEL_0d6cea63e319436ba5ffe35fac7b48cd","IPY_MODEL_fe168914334a4410b636e0b5cbd83374"],"layout":"IPY_MODEL_285457ce503a4f45b56945d7b668ec15"}},"10a55103bba642b88790b50f38496c8f":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_9a70d075718a4202805fd1fa76802851","IPY_MODEL_d3d57735e97f44a19a071ba98fd40242","IPY_MODEL_08c631bc03574fe99133eb7d69c75bff"],"layout":"IPY_MODEL_cf5db5f719d14023b730f29f3d049c7a"}},"125aca04caf44b07947796220e514272":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"12c20e27b49548ecb2b54bf606cea41c":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":"inline-flex","flex":null,"flex_flow":"row wrap","grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":"hidden","width":"100%"}},"154b076c6155420f8cf8ed504e30ad8a":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_ddb9b86b47ae4c8ead9f4ff7468ff3c3","placeholder":"ā","style":"IPY_MODEL_7ce48edc79e642e4a607efe9705b635e","value":" 18/18 [00:00<00:00, 336.65it/s]"}},"15e8f0621e004c889476c420a2d56265":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_c5d110f413944d04bf60cb2b507dd353","placeholder":"ā","style":"IPY_MODEL_ac4678ae4a11413cb74e37eb920553a3","value":" 18/18 [00:00<00:00, 289.13it/s]"}},"17e785d1e24545158d07969460ea99ed":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"18e7e8fac53d48bc9a3f5f78689d4cd0":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"1ce0de419d8e49d48894f2da5268329a":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"1d526e4320ae4bd681f5e0ad3c94d5f9":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"1f2e3b4cc744473ca7e23ed29e901b6a":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"2002ad771f0d4db2947fc82d9017689a":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_d24137ffd27c4f3699ebceffd8841e62","placeholder":"ā","style":"IPY_MODEL_e98ea7383e21464db726388a93233ce5","value":"Validation DataLoader 0: 100%"}},"20c2a614faae43219fd270f12fbfe208":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"221c3ce48a1349328f181c53ee7e9e90":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":"2","flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"229e56460901448cacb717fcc98f89e0":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_5565ef9e06a34a56aab1a6bbc480b1f8","placeholder":"ā","style":"IPY_MODEL_1f2e3b4cc744473ca7e23ed29e901b6a","value":"Sanity Checking DataLoader 0: 100%"}},"24b770cc035b453fa0e6d4f1d067721b":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":"inline-flex","flex":null,"flex_flow":"row wrap","grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":"hidden","width":"100%"}},"25e13485b1e6481d98ae6f61110a8f36":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"266255f5f60944ff9981122bb8dcfbbc":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":"inline-flex","flex":null,"flex_flow":"row wrap","grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":"hidden","width":"100%"}},"272a5bb6857d48c7b07a55ff1b56a04a":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"","description":"","description_tooltip":null,"layout":"IPY_MODEL_6abbf5dc589f4b51a473aa299c57b87b","max":18,"min":0,"orientation":"horizontal","style":"IPY_MODEL_bb06a11d60124d01a4244b01d92b61cd","value":18}},"285457ce503a4f45b56945d7b668ec15":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":"inline-flex","flex":null,"flex_flow":"row wrap","grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":"hidden","width":"100%"}},"28e11b013ee844b9b614f7c488a9b031":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_a905f7e6e2fd4d4ea491e3d522d6e878","IPY_MODEL_db407247a0b143dca91745f971a67f11","IPY_MODEL_ef259e3450a545aeb6ff8effab8ff956"],"layout":"IPY_MODEL_c3d49b64ab8e43eca2dae95dcc7d976c"}},"2a0d4ce109c54e5d8007c2796679c4bf":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":"2","flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"2ad3191c9a8a4315b6c871f9d138edad":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":"2","flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"2b29be21efca4c3f98a990b81430c920":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":"2","flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"2ba188939aba4aecba21113efe89867f":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"","description":"","description_tooltip":null,"layout":"IPY_MODEL_2a0d4ce109c54e5d8007c2796679c4bf","max":18,"min":0,"orientation":"horizontal","style":"IPY_MODEL_ab93f0462a454a14865e1350ae8fbcbf","value":18}},"2c3850495c68413f9c60db92872398b5":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_229e56460901448cacb717fcc98f89e0","IPY_MODEL_6c4e67d7e306425d809db2242e13680e","IPY_MODEL_aea4cbe701054cc491e9e0b87a129c61"],"layout":"IPY_MODEL_12c20e27b49548ecb2b54bf606cea41c"}},"2c3c5257013f4b45953ab4fb8c736c03":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"2d8781528e3c4d7d9040e8731332fa25":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":"inline-flex","flex":null,"flex_flow":"row wrap","grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":"hidden","width":"100%"}},"2e47e76defa64ad29a4a64fae33ea4fb":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_4bef892d30c64038b73a4bea27677285","placeholder":"ā","style":"IPY_MODEL_c706b60b6dca435184c161347f808719","value":"Validation DataLoader 0: 100%"}},"2e92171412c44c1f8d6230d0a94afcd6":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"","description":"","description_tooltip":null,"layout":"IPY_MODEL_4b5b3fe81ae14366b81dad2df35eb3c1","max":18,"min":0,"orientation":"horizontal","style":"IPY_MODEL_cfea0a64c6ab4decb6bafbf0527c96ba","value":18}},"2ebdff7919d943c9ac1c7ab7a3e449d4":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":"2","flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"2fd5bd4589584f718e219b6165ec4a5b":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"30afe0b88221426780ec9570767d664c":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_3552d345d2b9443d9e8a3d5337e97e4d","IPY_MODEL_4c9c2cc6f041497991b0183decfce8c8","IPY_MODEL_6f3c8bc376ac4604a97ba121da0974ba"],"layout":"IPY_MODEL_0b82189daceb4258a42021ba78690ea9"}},"33c7b03fd1ef433ebfc87ba3d98186b9":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":"inline-flex","flex":null,"flex_flow":"row wrap","grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":"hidden","width":"100%"}},"3552d345d2b9443d9e8a3d5337e97e4d":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_060f7364f1ff4278916d38a14f713158","placeholder":"ā","style":"IPY_MODEL_36afe8739c7249ef9a5442711e6d4b54","value":"Validation DataLoader 0: 100%"}},"36afe8739c7249ef9a5442711e6d4b54":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"38359b5fd54643b585a1fe4aebb79d41":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"","description":"","description_tooltip":null,"layout":"IPY_MODEL_970a0e49d62b40bea8563329dcd5b0c9","max":18,"min":0,"orientation":"horizontal","style":"IPY_MODEL_4fe3c13b4e304e9499157e13d0f1209b","value":18}},"386eeb312b5a4f76a1c632087c878e57":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"38f515dc2ac5437a9b8cc4fd1ea29917":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":"2","flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"39884943683441759ba6dcf352c90405":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"3c0a3ac09c4b4aec90dae6b607d70b96":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_2fd5bd4589584f718e219b6165ec4a5b","placeholder":"ā","style":"IPY_MODEL_bd48436a15224ba9a973ff6fe8f1f225","value":" 18/18 [00:00<00:00, 206.67it/s]"}},"3d989fda54b24e4d86a559f72b6cf8df":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"3eaf8d9c4d99437cadad546d34032899":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_b5ebcd2fba784ec884fc7d299978909e","IPY_MODEL_2e92171412c44c1f8d6230d0a94afcd6","IPY_MODEL_5de02ad7d86741078f22e4c49161d1c1"],"layout":"IPY_MODEL_63d0043fe487436b8c097840fd104f15"}},"421ef739e11c4513a135fd390cbe9df7":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"439e7bbe5a3b42b8a7624e9ea1077d2b":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_ed5814b2ff7f41f19638e361e24b3708","IPY_MODEL_a8754ff71d844cb8bc4ab09ce27e1fb9","IPY_MODEL_a1c2ffffca954d0f8c95a46b43e73488"],"layout":"IPY_MODEL_711549fa30cc49df958f9d098bcd4efc"}},"49bd52bd9b994e34a856aa3bec0315a1":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"4b5b3fe81ae14366b81dad2df35eb3c1":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":"2","flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"4bef892d30c64038b73a4bea27677285":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"4c9c2cc6f041497991b0183decfce8c8":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"","description":"","description_tooltip":null,"layout":"IPY_MODEL_2b29be21efca4c3f98a990b81430c920","max":18,"min":0,"orientation":"horizontal","style":"IPY_MODEL_575ac4e65be3473faadc818321c42945","value":18}},"4cba4a327682463987fab5f982905fb5":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"4db0c6d08d8c4079998be8610628a71b":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"4e63aaa91bd0467883072ef65fff9451":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"4fa5ffc0608e49b49d02a769107fdae4":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"4fe3c13b4e304e9499157e13d0f1209b":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"510cd309ecff4c6aae1d1113cb827479":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"51710c0572cf41208c5deacf1c2d4179":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"5565ef9e06a34a56aab1a6bbc480b1f8":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"575ac4e65be3473faadc818321c42945":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"57cd2458449b4d0db0a4ca49a92f9631":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"5852bcd7233940c9b6d96d8ea785f452":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":"inline-flex","flex":null,"flex_flow":"row wrap","grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":"hidden","width":"100%"}},"586555098a9743318e63168b5cf48e52":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"5924bff92eab496a949003cab90251e3":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"","description":"","description_tooltip":null,"layout":"IPY_MODEL_cd6d36200b0f43cbbdc50cf439209277","max":18,"min":0,"orientation":"horizontal","style":"IPY_MODEL_20c2a614faae43219fd270f12fbfe208","value":18}},"5a94fd54d1554f4aba15af8b3e448d32":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"5ac09c5dd8744f889565d58ed7928b9a":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"5b50ca51622242da829dacc9a1ee2316":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"5d457585598c4d8eb3ad18ab90dcdc19":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":"inline-flex","flex":null,"flex_flow":"row wrap","grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":"100%"}},"5de02ad7d86741078f22e4c49161d1c1":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_64ebf2ff8eba4ab5b629d6fd7496cded","placeholder":"ā","style":"IPY_MODEL_d0237cd901d840efbbb1efd0d84d1237","value":" 18/18 [00:00<00:00, 139.85it/s]"}},"5e7f42fce1dd4425b0719285af019b2b":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"6263583c14af4591b0abc2a3d1239561":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"63d0043fe487436b8c097840fd104f15":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":"inline-flex","flex":null,"flex_flow":"row wrap","grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":"hidden","width":"100%"}},"63dad850a0a44207b79c9a89aecc929d":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_6d2e1c8107634cfa8cadca0935ec592d","placeholder":"ā","style":"IPY_MODEL_4db0c6d08d8c4079998be8610628a71b","value":"Validation DataLoader 0: 100%"}},"64ebf2ff8eba4ab5b629d6fd7496cded":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"66f1ebaa14bd4caca5ce8f2aedc0a757":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_dc6f61bd3f4246d08fa7b01c70df578d","IPY_MODEL_38359b5fd54643b585a1fe4aebb79d41","IPY_MODEL_f392ab89772b46768c7e5b78adfddd84"],"layout":"IPY_MODEL_8f7baa0f934f4bad9c431c139ce820a1"}},"671d1d459f84406ead2e225ec146a905":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"6abbf5dc589f4b51a473aa299c57b87b":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":"2","flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"6c4e67d7e306425d809db2242e13680e":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"","description":"","description_tooltip":null,"layout":"IPY_MODEL_a070e992b4894c928853f27f8c601686","max":2,"min":0,"orientation":"horizontal","style":"IPY_MODEL_4e63aaa91bd0467883072ef65fff9451","value":2}},"6d2e1c8107634cfa8cadca0935ec592d":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"6dee469934e54531955cbfbd40374dcb":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"","description":"","description_tooltip":null,"layout":"IPY_MODEL_d6a07db7cfd143148c1a72b3a44ebb52","max":18,"min":0,"orientation":"horizontal","style":"IPY_MODEL_79dbe930b3d04dd89a278c18a15afcf3","value":18}},"6f3c8bc376ac4604a97ba121da0974ba":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_02832a8053b9468ba1527155e9b2889c","placeholder":"ā","style":"IPY_MODEL_0ceda6ced454421bbccf50c82eb4188e","value":" 18/18 [00:00<00:00, 313.02it/s]"}},"6f4e7541360e492c92f42b2995d43e22":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":"2","flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"6f7067ec48cc4175ab887fb22537fc1a":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"711549fa30cc49df958f9d098bcd4efc":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":"inline-flex","flex":null,"flex_flow":"row wrap","grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":"hidden","width":"100%"}},"719319145aeb4c21b7abb76f4be8e93a":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"","description":"","description_tooltip":null,"layout":"IPY_MODEL_d9b7d60c2e164e779c689761bbb254f4","max":18,"min":0,"orientation":"horizontal","style":"IPY_MODEL_49bd52bd9b994e34a856aa3bec0315a1","value":18}},"721ec9b44337410ebb3137df63de72dd":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"727042c0c4ee413a972b599aba5f8679":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":"inline-flex","flex":null,"flex_flow":"row wrap","grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":"hidden","width":"100%"}},"72bbc6aa8c45498784faa9dfc972e212":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_0ae0f77a8393470c91307205b464e940","IPY_MODEL_ecd6af55136c49f3ba70774482e56e1b","IPY_MODEL_bf07413b8bdc4c68bf92c6374615582b"],"layout":"IPY_MODEL_266255f5f60944ff9981122bb8dcfbbc"}},"738cfaf31b724e29b13ff764e61d76f8":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"","description":"","description_tooltip":null,"layout":"IPY_MODEL_9dee68a1b5534bd1920c9012f6c5c8f8","max":18,"min":0,"orientation":"horizontal","style":"IPY_MODEL_1ce0de419d8e49d48894f2da5268329a","value":18}},"73980a3ec1e841839b91ba7426c8779d":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"758c15ec4cf1470ea2ee45068b47b66d":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_c116c4803be14691bc4d2c6357473fd9","IPY_MODEL_6dee469934e54531955cbfbd40374dcb","IPY_MODEL_15e8f0621e004c889476c420a2d56265"],"layout":"IPY_MODEL_727042c0c4ee413a972b599aba5f8679"}},"7605e86d96cf47efb73d43c454229284":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"","description":"","description_tooltip":null,"layout":"IPY_MODEL_fd0ae0166e404960b7889f4326f8c54e","max":18,"min":0,"orientation":"horizontal","style":"IPY_MODEL_0026a4e66ad64192a2474f8b175ecab6","value":18}},"764a8318dcac45b6bbb717d7c4c24e1c":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"7853abed7bb540aabd8540d19522f361":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"79a6ce351bc04bbd8e57956e59ff3458":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":"2","flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"79dbe930b3d04dd89a278c18a15afcf3":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"7b29cabf32614e54b725690a251400c9":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":"inline-flex","flex":null,"flex_flow":"row wrap","grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":"hidden","width":"100%"}},"7b363eeb0dad45cfad3048142a6a45ce":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"7ce48edc79e642e4a607efe9705b635e":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"7d5b27baa1ef4a8abf67bf06efcbe469":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":"2","flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"7ddb7981b4e940f8b52dfa65536b47ed":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_b7d7a5fa280d44e19f161361bc1f449c","IPY_MODEL_738cfaf31b724e29b13ff764e61d76f8","IPY_MODEL_b25da60388584260973ee3682c3d43d6"],"layout":"IPY_MODEL_2d8781528e3c4d7d9040e8731332fa25"}},"7fc7b2f0dfc54cd3aa4272a9589b0187":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_eb6221dc5bbf4595b610e0fc2a38b459","IPY_MODEL_2ba188939aba4aecba21113efe89867f","IPY_MODEL_3c0a3ac09c4b4aec90dae6b607d70b96"],"layout":"IPY_MODEL_d04271146ae640d589d5df157f177e88"}},"81c2e4202e9f438ba8ed8204b6134fe2":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_a5d70f79573b4042bf5b90473e7ac1d8","placeholder":"ā","style":"IPY_MODEL_0d4f9f833c754a0dac509b43447e2944","value":" 0/18 [00:00<?, ?it/s, v_num=2, train_loss_step=4.700, train_loss_epoch=4.640]"}},"8301d79f4459423c8c4a6f047919a122":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_8b800528612d409a88e5eaaa1220c2a8","placeholder":"ā","style":"IPY_MODEL_d502f6b7aac14c7a8aaf475d6878818f","value":"Validation DataLoader 0: 100%"}},"833f3cce10c54ee79c406cdd49725646":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"83931a176c3641049570d6a2ae383ec4":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"8493674c9a0d4efba5ae31963d68739c":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"881d31df87b14ff2b26c2fbc6ec0332c":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"8869083fbd7e414c9646d991fb81a4fa":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_a0affbd26b114033b9822729cdc74a20","placeholder":"ā","style":"IPY_MODEL_2c3c5257013f4b45953ab4fb8c736c03","value":" 18/18 [00:00<00:00, 285.91it/s]"}},"8ada728011e948498997edf37d29369b":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_2002ad771f0d4db2947fc82d9017689a","IPY_MODEL_5924bff92eab496a949003cab90251e3","IPY_MODEL_e13eb8312d754580a78f7b96884c2c17"],"layout":"IPY_MODEL_99c6897577124b8a9e526cd170e6c13b"}},"8b800528612d409a88e5eaaa1220c2a8":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"8c10989f00744514a49f4c12b83e93cb":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"8f259a2ca60e45dc81fd5033dbd283e3":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":"2","flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"8f7baa0f934f4bad9c431c139ce820a1":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":"inline-flex","flex":null,"flex_flow":"row wrap","grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":"hidden","width":"100%"}},"8fcb21bf89af44e1bd0ac0a4c60fd759":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"9466f6af10b84050a489b53e4d89deac":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"947dcc0f0cd04fac8fa67576931a25b5":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":"inline-flex","flex":null,"flex_flow":"row wrap","grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":"hidden","width":"100%"}},"95abfc97c10f423ba411db620a2aa537":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":"inline-flex","flex":null,"flex_flow":"row wrap","grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":"hidden","width":"100%"}},"96baba250a4a498fa028a326e0f9df73":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"970a0e49d62b40bea8563329dcd5b0c9":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":"2","flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"98a562b85c6a493eacdeb22154e3cea7":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_63dad850a0a44207b79c9a89aecc929d","IPY_MODEL_719319145aeb4c21b7abb76f4be8e93a","IPY_MODEL_aabff7e366814212a31418f3432e4f1e"],"layout":"IPY_MODEL_95abfc97c10f423ba411db620a2aa537"}},"99c6897577124b8a9e526cd170e6c13b":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":"inline-flex","flex":null,"flex_flow":"row wrap","grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":"hidden","width":"100%"}},"9a70d075718a4202805fd1fa76802851":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_9c3c058492c34beda090ec66a08b4005","placeholder":"ā","style":"IPY_MODEL_5ac09c5dd8744f889565d58ed7928b9a","value":"Validation DataLoader 0: 100%"}},"9bece872a1ed4add8208866392ea143b":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_386eeb312b5a4f76a1c632087c878e57","placeholder":"ā","style":"IPY_MODEL_57cd2458449b4d0db0a4ca49a92f9631","value":"Predicting DataLoader 0: 100%"}},"9c3c058492c34beda090ec66a08b4005":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"9dee68a1b5534bd1920c9012f6c5c8f8":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":"2","flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"9fe640fee1c147a9ba4505e75ffae699":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_0de07aebf5454c9fbdc07f3ec49ce2b4","placeholder":"ā","style":"IPY_MODEL_dae67dcea0944c0ca484e03ba2c942a2","value":"Validation DataLoader 0: 100%"}},"a070e992b4894c928853f27f8c601686":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":"2","flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"a0affbd26b114033b9822729cdc74a20":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"a1c2ffffca954d0f8c95a46b43e73488":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_510cd309ecff4c6aae1d1113cb827479","placeholder":"ā","style":"IPY_MODEL_ea60b0c85bd241ef91b7b03564c1fad3","value":" 18/18 [00:00<00:00, 381.94it/s]"}},"a1e4be7d02ef4785bcb4c9e7596f6a15":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_1d526e4320ae4bd681f5e0ad3c94d5f9","placeholder":"ā","style":"IPY_MODEL_25e13485b1e6481d98ae6f61110a8f36","value":"Epoch 111: 0%"}},"a212d585282c40a39f376e0e36fd29b3":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"a335868ce56240f1bf7833985df1a646":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"a341fb6e5ecf488b955c23ab4d9f9779":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"a3c40c8a875547958dc50bc2a01f1e57":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"a59a33581f814a129a45fe82cc98966b":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"a5d70f79573b4042bf5b90473e7ac1d8":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"a8754ff71d844cb8bc4ab09ce27e1fb9":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"","description":"","description_tooltip":null,"layout":"IPY_MODEL_38f515dc2ac5437a9b8cc4fd1ea29917","max":18,"min":0,"orientation":"horizontal","style":"IPY_MODEL_6263583c14af4591b0abc2a3d1239561","value":18}},"a905f7e6e2fd4d4ea491e3d522d6e878":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_dbbffc3348794137a613b92151d81776","placeholder":"ā","style":"IPY_MODEL_8c10989f00744514a49f4c12b83e93cb","value":"Validation DataLoader 0: 100%"}},"a9d402da00474856b24da8c16a498534":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"","description":"","description_tooltip":null,"layout":"IPY_MODEL_2ebdff7919d943c9ac1c7ab7a3e449d4","max":18,"min":0,"orientation":"horizontal","style":"IPY_MODEL_7853abed7bb540aabd8540d19522f361","value":18}},"aa05deb9e7aa46d59baf0f26f029d58d":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":"2","flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"aabff7e366814212a31418f3432e4f1e":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_671d1d459f84406ead2e225ec146a905","placeholder":"ā","style":"IPY_MODEL_e3cdb4e2119f410f9d9cb23c299d4366","value":" 18/18 [00:00<00:00, 327.18it/s]"}},"ab93f0462a454a14865e1350ae8fbcbf":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"abb97079bd394f20975ea9c8bc3b45b4":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"abc026faa7844ac4b506020f1590aba1":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"ac4678ae4a11413cb74e37eb920553a3":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"aea4cbe701054cc491e9e0b87a129c61":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_c51be98e0dca43dca8636a7c57681e30","placeholder":"ā","style":"IPY_MODEL_73980a3ec1e841839b91ba7426c8779d","value":" 2/2 [00:00<00:00, 133.07it/s]"}},"b25da60388584260973ee3682c3d43d6":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_8fcb21bf89af44e1bd0ac0a4c60fd759","placeholder":"ā","style":"IPY_MODEL_421ef739e11c4513a135fd390cbe9df7","value":" 18/18 [00:00<00:00, 361.93it/s]"}},"b3e47172a5774f7dabf9afe2f2a2c500":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_51710c0572cf41208c5deacf1c2d4179","placeholder":"ā","style":"IPY_MODEL_c373f798b5af4d348930840d9f90f96f","value":"Validation DataLoader 0: 100%"}},"b5ebcd2fba784ec884fc7d299978909e":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_a3c40c8a875547958dc50bc2a01f1e57","placeholder":"ā","style":"IPY_MODEL_125aca04caf44b07947796220e514272","value":"Validation DataLoader 0: 100%"}},"b694b3ab3cf14361a5c3291878686a48":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"b7d7a5fa280d44e19f161361bc1f449c":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_4fa5ffc0608e49b49d02a769107fdae4","placeholder":"ā","style":"IPY_MODEL_18e7e8fac53d48bc9a3f5f78689d4cd0","value":"Validation DataLoader 0: 100%"}},"ba442028da3744a684637564164ff036":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_9fe640fee1c147a9ba4505e75ffae699","IPY_MODEL_a9d402da00474856b24da8c16a498534","IPY_MODEL_05b6d67cd4ba4f5ebf0ed9fbf769622b"],"layout":"IPY_MODEL_947dcc0f0cd04fac8fa67576931a25b5"}},"bb06a11d60124d01a4244b01d92b61cd":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"bc1a650bcc9e4c3dbd973329707748da":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"bd48436a15224ba9a973ff6fe8f1f225":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"bf07413b8bdc4c68bf92c6374615582b":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_586555098a9743318e63168b5cf48e52","placeholder":"ā","style":"IPY_MODEL_a335868ce56240f1bf7833985df1a646","value":" 18/18 [00:00<00:00, 303.81it/s]"}},"c116c4803be14691bc4d2c6357473fd9":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_a59a33581f814a129a45fe82cc98966b","placeholder":"ā","style":"IPY_MODEL_4cba4a327682463987fab5f982905fb5","value":"Validation DataLoader 0: 100%"}},"c2f8fd113fb54a8583d1355411bad615":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_b3e47172a5774f7dabf9afe2f2a2c500","IPY_MODEL_c3ac395b59d74660b99237212e049f5b","IPY_MODEL_0856b7582be344babcc73be8eed57297"],"layout":"IPY_MODEL_5852bcd7233940c9b6d96d8ea785f452"}},"c373f798b5af4d348930840d9f90f96f":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"c3ac395b59d74660b99237212e049f5b":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"","description":"","description_tooltip":null,"layout":"IPY_MODEL_8f259a2ca60e45dc81fd5033dbd283e3","max":18,"min":0,"orientation":"horizontal","style":"IPY_MODEL_ca007d61e4694fe7bfd25f190e5f2956","value":18}},"c3d49b64ab8e43eca2dae95dcc7d976c":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":"inline-flex","flex":null,"flex_flow":"row wrap","grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":"hidden","width":"100%"}},"c51be98e0dca43dca8636a7c57681e30":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"c57ec038445243efb63b2060ddefc4cf":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"success","description":"","description_tooltip":null,"layout":"IPY_MODEL_221c3ce48a1349328f181c53ee7e9e90","max":18,"min":0,"orientation":"horizontal","style":"IPY_MODEL_bc1a650bcc9e4c3dbd973329707748da","value":18}},"c5a6bcafaaa34d8ea027f0677c0d1f05":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"c5b32f0d793e457fa04a57126d9c6120":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"c5d110f413944d04bf60cb2b507dd353":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"c706b60b6dca435184c161347f808719":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"c8d9e2d5beab4365911e53f4812e0ff8":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"danger","description":"","description_tooltip":null,"layout":"IPY_MODEL_2ad3191c9a8a4315b6c871f9d138edad","max":18,"min":0,"orientation":"horizontal","style":"IPY_MODEL_83931a176c3641049570d6a2ae383ec4","value":0}},"ca007d61e4694fe7bfd25f190e5f2956":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"cbf74c9f21c94e06acedbe59ae38a8ce":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"cd6d36200b0f43cbbdc50cf439209277":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":"2","flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"cdea0a05652f496e87a053c9293834d1":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"cf5db5f719d14023b730f29f3d049c7a":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":"inline-flex","flex":null,"flex_flow":"row wrap","grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":"hidden","width":"100%"}},"cfb8e5b021ac481c9fb7d0a74e0093dc":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"cfea0a64c6ab4decb6bafbf0527c96ba":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"ProgressStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"ProgressStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","bar_color":null,"description_width":""}},"d0237cd901d840efbbb1efd0d84d1237":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"d04271146ae640d589d5df157f177e88":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":"inline-flex","flex":null,"flex_flow":"row wrap","grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":"hidden","width":"100%"}},"d24137ffd27c4f3699ebceffd8841e62":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"d3d57735e97f44a19a071ba98fd40242":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"","description":"","description_tooltip":null,"layout":"IPY_MODEL_f2728918f9bc4c02833b93f2e758adbb","max":18,"min":0,"orientation":"horizontal","style":"IPY_MODEL_833f3cce10c54ee79c406cdd49725646","value":18}},"d4051dc8e4374c5785a4a038dff26046":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"","description":"","description_tooltip":null,"layout":"IPY_MODEL_6f4e7541360e492c92f42b2995d43e22","max":18,"min":0,"orientation":"horizontal","style":"IPY_MODEL_6f7067ec48cc4175ab887fb22537fc1a","value":18}},"d502f6b7aac14c7a8aaf475d6878818f":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"d6a07db7cfd143148c1a72b3a44ebb52":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":"2","flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"d6c5cd33636a46e787508e55e12e5532":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_e2c9bdece2bb4b2eb1e7fa552b00450e","IPY_MODEL_272a5bb6857d48c7b07a55ff1b56a04a","IPY_MODEL_019f47d763dc413ba614d6cfdf341baa"],"layout":"IPY_MODEL_33c7b03fd1ef433ebfc87ba3d98186b9"}},"d9b7d60c2e164e779c689761bbb254f4":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":"2","flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"d9f8ee949dc847e68a057fb8a87eea7e":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_a1e4be7d02ef4785bcb4c9e7596f6a15","IPY_MODEL_c8d9e2d5beab4365911e53f4812e0ff8","IPY_MODEL_81c2e4202e9f438ba8ed8204b6134fe2"],"layout":"IPY_MODEL_5d457585598c4d8eb3ad18ab90dcdc19"}},"dae67dcea0944c0ca484e03ba2c942a2":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"db407247a0b143dca91745f971a67f11":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"","description":"","description_tooltip":null,"layout":"IPY_MODEL_79a6ce351bc04bbd8e57956e59ff3458","max":18,"min":0,"orientation":"horizontal","style":"IPY_MODEL_721ec9b44337410ebb3137df63de72dd","value":18}},"dbbffc3348794137a613b92151d81776":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"dc6f61bd3f4246d08fa7b01c70df578d":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_7b363eeb0dad45cfad3048142a6a45ce","placeholder":"ā","style":"IPY_MODEL_cbf74c9f21c94e06acedbe59ae38a8ce","value":"Validation DataLoader 0: 100%"}},"dd71dcbdd8eb43f0a61bbc17f8ebf153":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":"inline-flex","flex":null,"flex_flow":"row wrap","grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":"100%"}},"ddb9b86b47ae4c8ead9f4ff7468ff3c3":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"e13eb8312d754580a78f7b96884c2c17":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_c5a6bcafaaa34d8ea027f0677c0d1f05","placeholder":"ā","style":"IPY_MODEL_fb5546894f2f41fe9bcad8afa0e0a607","value":" 18/18 [00:00<00:00, 299.10it/s]"}},"e2c9bdece2bb4b2eb1e7fa552b00450e":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_cfb8e5b021ac481c9fb7d0a74e0093dc","placeholder":"ā","style":"IPY_MODEL_764a8318dcac45b6bbb717d7c4c24e1c","value":"Validation DataLoader 0: 100%"}},"e3bcb7f095674665a4263a31198356b0":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"e3cdb4e2119f410f9d9cb23c299d4366":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"e5ebcb58037d4bd49beccaab3b0b843a":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"e6a54dcb7ca243efa1d24708342f20ad":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"e6cbd39b82bb45a0a970885f687e12c5":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"e74d8f4ad9944ff8bad0ceb755c6e70f":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"e98ea7383e21464db726388a93233ce5":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"ea60b0c85bd241ef91b7b03564c1fad3":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"eb6221dc5bbf4595b610e0fc2a38b459":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_e6a54dcb7ca243efa1d24708342f20ad","placeholder":"ā","style":"IPY_MODEL_e5ebcb58037d4bd49beccaab3b0b843a","value":"Validation DataLoader 0: 100%"}},"ec2785af9d934235abdd9f2030180f71":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_9bece872a1ed4add8208866392ea143b","IPY_MODEL_c57ec038445243efb63b2060ddefc4cf","IPY_MODEL_ff9efd82afbd4870b6cee44c9dfe5b09"],"layout":"IPY_MODEL_dd71dcbdd8eb43f0a61bbc17f8ebf153"}},"ecd6af55136c49f3ba70774482e56e1b":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"FloatProgressModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"FloatProgressModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"ProgressView","bar_style":"","description":"","description_tooltip":null,"layout":"IPY_MODEL_aa05deb9e7aa46d59baf0f26f029d58d","max":18,"min":0,"orientation":"horizontal","style":"IPY_MODEL_a212d585282c40a39f376e0e36fd29b3","value":18}},"ed5814b2ff7f41f19638e361e24b3708":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_5a94fd54d1554f4aba15af8b3e448d32","placeholder":"ā","style":"IPY_MODEL_0b3093c72da94fee93073cbdcd42da04","value":"Validation DataLoader 0: 100%"}},"ef259e3450a545aeb6ff8effab8ff956":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_f6ebdc02aa7a4f898ba8a130042dd0c1","placeholder":"ā","style":"IPY_MODEL_fdf3e4bb73cd44449d28f21d0c2759a2","value":" 18/18 [00:00<00:00, 356.16it/s]"}},"f2728918f9bc4c02833b93f2e758adbb":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":"2","flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"f392ab89772b46768c7e5b78adfddd84":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_39884943683441759ba6dcf352c90405","placeholder":"ā","style":"IPY_MODEL_8493674c9a0d4efba5ae31963d68739c","value":" 18/18 [00:00<00:00, 301.23it/s]"}},"f62cd37312c34e6ca26d4d3fc1fd988e":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_881d31df87b14ff2b26c2fbc6ec0332c","placeholder":"ā","style":"IPY_MODEL_3d989fda54b24e4d86a559f72b6cf8df","value":"Validation DataLoader 0: 100%"}},"f6ebdc02aa7a4f898ba8a130042dd0c1":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"f7351fa56f2f4a75b72b36f0295680d0":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_8301d79f4459423c8c4a6f047919a122","IPY_MODEL_d4051dc8e4374c5785a4a038dff26046","IPY_MODEL_8869083fbd7e414c9646d991fb81a4fa"],"layout":"IPY_MODEL_24b770cc035b453fa0e6d4f1d067721b"}},"fb5546894f2f41fe9bcad8afa0e0a607":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"fb5c206785454e0c855f4f9be9c02613":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HBoxModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HBoxModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HBoxView","box_style":"","children":["IPY_MODEL_f62cd37312c34e6ca26d4d3fc1fd988e","IPY_MODEL_7605e86d96cf47efb73d43c454229284","IPY_MODEL_154b076c6155420f8cf8ed504e30ad8a"],"layout":"IPY_MODEL_7b29cabf32614e54b725690a251400c9"}},"fd0ae0166e404960b7889f4326f8c54e":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":"2","flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"fd87f2b9954d4fc788faba7f8585c5ec":{"model_module":"@jupyter-widgets/base","model_module_version":"1.2.0","model_name":"LayoutModel","state":{"_model_module":"@jupyter-widgets/base","_model_module_version":"1.2.0","_model_name":"LayoutModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"LayoutView","align_content":null,"align_items":null,"align_self":null,"border":null,"bottom":null,"display":null,"flex":null,"flex_flow":null,"grid_area":null,"grid_auto_columns":null,"grid_auto_flow":null,"grid_auto_rows":null,"grid_column":null,"grid_gap":null,"grid_row":null,"grid_template_areas":null,"grid_template_columns":null,"grid_template_rows":null,"height":null,"justify_content":null,"justify_items":null,"left":null,"margin":null,"max_height":null,"max_width":null,"min_height":null,"min_width":null,"object_fit":null,"object_position":null,"order":null,"overflow":null,"overflow_x":null,"overflow_y":null,"padding":null,"right":null,"top":null,"visibility":null,"width":null}},"fdf3e4bb73cd44449d28f21d0c2759a2":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"DescriptionStyleModel","state":{"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"DescriptionStyleModel","_view_count":null,"_view_module":"@jupyter-widgets/base","_view_module_version":"1.2.0","_view_name":"StyleView","description_width":""}},"fe168914334a4410b636e0b5cbd83374":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_e3bcb7f095674665a4263a31198356b0","placeholder":"ā","style":"IPY_MODEL_5e7f42fce1dd4425b0719285af019b2b","value":" 18/18 [00:00<00:00, 302.15it/s]"}},"ff9efd82afbd4870b6cee44c9dfe5b09":{"model_module":"@jupyter-widgets/controls","model_module_version":"1.5.0","model_name":"HTMLModel","state":{"_dom_classes":[],"_model_module":"@jupyter-widgets/controls","_model_module_version":"1.5.0","_model_name":"HTMLModel","_view_count":null,"_view_module":"@jupyter-widgets/controls","_view_module_version":"1.5.0","_view_name":"HTMLView","description":"","description_tooltip":null,"layout":"IPY_MODEL_fd87f2b9954d4fc788faba7f8585c5ec","placeholder":"ā","style":"IPY_MODEL_cdea0a05652f496e87a053c9293834d1","value":" 18/18 [00:00<00:00, 109.33it/s]"}}} +</script> +<script id="quarto-html-after-body" type="application/javascript"> +window.document.addEventListener("DOMContentLoaded", function (event) { + const toggleBodyColorMode = (bsSheetEl) => { + const mode = bsSheetEl.getAttribute("data-mode"); + const bodyEl = window.document.querySelector("body"); + if (mode === "dark") { + bodyEl.classList.add("quarto-dark"); + bodyEl.classList.remove("quarto-light"); + } else { + bodyEl.classList.add("quarto-light"); + bodyEl.classList.remove("quarto-dark"); + } + } + const toggleBodyColorPrimary = () => { + const bsSheetEl = window.document.querySelector("link#quarto-bootstrap"); + if (bsSheetEl) { + toggleBodyColorMode(bsSheetEl); + } + } + toggleBodyColorPrimary(); + const icon = "ī§"; + const anchorJS = new window.AnchorJS(); + anchorJS.options = { + placement: 'right', + icon: icon + }; + anchorJS.add('.anchored'); + const isCodeAnnotation = (el) => { + for (const clz of el.classList) { + if (clz.startsWith('code-annotation-')) { + return true; + } + } + return false; + } + const clipboard = new window.ClipboardJS('.code-copy-button', { + text: function(trigger) { + const codeEl = trigger.previousElementSibling.cloneNode(true); + for (const childEl of codeEl.children) { + if (isCodeAnnotation(childEl)) { + childEl.remove(); + } + } + return codeEl.innerText; + } + }); + clipboard.on('success', function(e) { + // button target + const button = e.trigger; + // don't keep focus + button.blur(); + // flash "checked" + button.classList.add('code-copy-button-checked'); + var currentTitle = button.getAttribute("title"); + button.setAttribute("title", "Copied!"); + let tooltip; + if (window.bootstrap) { + button.setAttribute("data-bs-toggle", "tooltip"); + button.setAttribute("data-bs-placement", "left"); + button.setAttribute("data-bs-title", "Copied!"); + tooltip = new bootstrap.Tooltip(button, + { trigger: "manual", + customClass: "code-copy-button-tooltip", + offset: [0, -8]}); + tooltip.show(); + } + setTimeout(function() { + if (tooltip) { + tooltip.hide(); + button.removeAttribute("data-bs-title"); + button.removeAttribute("data-bs-toggle"); + button.removeAttribute("data-bs-placement"); + } + button.setAttribute("title", currentTitle); + button.classList.remove('code-copy-button-checked'); + }, 1000); + // clear code selection + e.clearSelection(); + }); + function tippyHover(el, contentFn) { + const config = { + allowHTML: true, + content: contentFn, + maxWidth: 500, + delay: 100, + arrow: false, + appendTo: function(el) { + return el.parentElement; + }, + interactive: true, + interactiveBorder: 10, + theme: 'quarto', + placement: 'bottom-start' + }; + window.tippy(el, config); + } + const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]'); + for (var i=0; i<noterefs.length; i++) { + const ref = noterefs[i]; + tippyHover(ref, function() { + // use id or data attribute instead here + let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href'); + try { href = new URL(href).hash; } catch {} + const id = href.replace(/^#\/?/, ""); + const note = window.document.getElementById(id); + return note.innerHTML; + }); + } + let selectedAnnoteEl; + const selectorForAnnotation = ( cell, annotation) => { + let cellAttr = 'data-code-cell="' + cell + '"'; + let lineAttr = 'data-code-annotation="' + annotation + '"'; + const selector = 'span[' + cellAttr + '][' + lineAttr + ']'; + return selector; + } + const selectCodeLines = (annoteEl) => { + const doc = window.document; + const targetCell = annoteEl.getAttribute("data-target-cell"); + const targetAnnotation = annoteEl.getAttribute("data-target-annotation"); + const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation)); + const lines = annoteSpan.getAttribute("data-code-lines").split(","); + const lineIds = lines.map((line) => { + return targetCell + "-" + line; + }) + let top = null; + let height = null; + let parent = null; + if (lineIds.length > 0) { + //compute the position of the single el (top and bottom and make a div) + const el = window.document.getElementById(lineIds[0]); + top = el.offsetTop; + height = el.offsetHeight; + parent = el.parentElement.parentElement; + if (lineIds.length > 1) { + const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]); + const bottom = lastEl.offsetTop + lastEl.offsetHeight; + height = bottom - top; + } + if (top !== null && height !== null && parent !== null) { + // cook up a div (if necessary) and position it + let div = window.document.getElementById("code-annotation-line-highlight"); + if (div === null) { + div = window.document.createElement("div"); + div.setAttribute("id", "code-annotation-line-highlight"); + div.style.position = 'absolute'; + parent.appendChild(div); + } + div.style.top = top - 2 + "px"; + div.style.height = height + 4 + "px"; + let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter"); + if (gutterDiv === null) { + gutterDiv = window.document.createElement("div"); + gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter"); + gutterDiv.style.position = 'absolute'; + const codeCell = window.document.getElementById(targetCell); + const gutter = codeCell.querySelector('.code-annotation-gutter'); + gutter.appendChild(gutterDiv); + } + gutterDiv.style.top = top - 2 + "px"; + gutterDiv.style.height = height + 4 + "px"; + } + selectedAnnoteEl = annoteEl; + } + }; + const unselectCodeLines = () => { + const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"]; + elementsIds.forEach((elId) => { + const div = window.document.getElementById(elId); + if (div) { + div.remove(); + } + }); + selectedAnnoteEl = undefined; + }; + // Attach click handler to the DT + const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); + for (const annoteDlNode of annoteDls) { + annoteDlNode.addEventListener('click', (event) => { + const clickedEl = event.target; + if (clickedEl !== selectedAnnoteEl) { + unselectCodeLines(); + const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active'); + if (activeEl) { + activeEl.classList.remove('code-annotation-active'); + } + selectCodeLines(clickedEl); + clickedEl.classList.add('code-annotation-active'); + } else { + // Unselect the line + unselectCodeLines(); + clickedEl.classList.remove('code-annotation-active'); + } + }); + } + const findCites = (el) => { + const parentEl = el.parentElement; + if (parentEl) { + const cites = parentEl.dataset.cites; + if (cites) { + return { + el, + cites: cites.split(' ') + }; + } else { + return findCites(el.parentElement) + } + } else { + return undefined; + } + }; + var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]'); + for (var i=0; i<bibliorefs.length; i++) { + const ref = bibliorefs[i]; + const citeInfo = findCites(ref); + if (citeInfo) { + tippyHover(citeInfo.el, function() { + var popup = window.document.createElement('div'); + citeInfo.cites.forEach(function(cite) { + var citeDiv = window.document.createElement('div'); + citeDiv.classList.add('hanging-indent'); + citeDiv.classList.add('csl-entry'); + var biblioDiv = window.document.getElementById('ref-' + cite); + if (biblioDiv) { + citeDiv.innerHTML = biblioDiv.innerHTML; + } + popup.appendChild(citeDiv); + }); + return popup.innerHTML; + }); + } + } +}); +</script> +</div> <!-- /content --> + + + +</body></html> \ No newline at end of file diff --git a/examples/nonnegativereconciliation.html b/examples/nonnegativereconciliation.html new file mode 100644 index 00000000..000e35e7 --- /dev/null +++ b/examples/nonnegativereconciliation.html @@ -0,0 +1,1303 @@ +<!DOCTYPE html> +<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head> + +<meta charset="utf-8"> +<meta name="generator" content="quarto-1.3.450"> + +<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes"> + + +<title>hierarchicalforecast - Non-Negative MinTrace</title> +<style> +code{white-space: pre-wrap;} +span.smallcaps{font-variant: small-caps;} +div.columns{display: flex; gap: min(4vw, 1.5em);} +div.column{flex: auto; overflow-x: auto;} +div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;} +ul.task-list{list-style: none;} +ul.task-list li input[type="checkbox"] { + width: 0.8em; + margin: 0 0.8em 0.2em -1em; /* quarto-specific, see https://github.com/quarto-dev/quarto-cli/issues/4556 */ + vertical-align: middle; +} +/* CSS for syntax highlighting */ +pre > code.sourceCode { white-space: pre; position: relative; } +pre > code.sourceCode > span { display: inline-block; line-height: 1.25; } +pre > code.sourceCode > span:empty { height: 1.2em; } +.sourceCode { overflow: visible; } +code.sourceCode > span { color: inherit; text-decoration: inherit; } +div.sourceCode { margin: 1em 0; } +pre.sourceCode { margin: 0; } +@media screen { +div.sourceCode { overflow: auto; } +} +@media print { +pre > code.sourceCode { white-space: pre-wrap; } +pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; } +} +pre.numberSource code + { counter-reset: source-line 0; } +pre.numberSource code > span + { position: relative; left: -4em; counter-increment: source-line; } +pre.numberSource code > span > a:first-child::before + { content: counter(source-line); + position: relative; left: -1em; text-align: right; vertical-align: baseline; + border: none; display: inline-block; + -webkit-touch-callout: none; -webkit-user-select: none; + -khtml-user-select: none; -moz-user-select: none; + -ms-user-select: none; user-select: none; + padding: 0 4px; width: 4em; + } +pre.numberSource { margin-left: 3em; padding-left: 4px; } +div.sourceCode + { } +@media screen { +pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; } +} +</style> + + +<script src="../site_libs/quarto-nav/quarto-nav.js"></script> +<script src="../site_libs/quarto-nav/headroom.min.js"></script> +<script src="../site_libs/clipboard/clipboard.min.js"></script> +<script src="../site_libs/quarto-search/autocomplete.umd.js"></script> +<script src="../site_libs/quarto-search/fuse.min.js"></script> +<script src="../site_libs/quarto-search/quarto-search.js"></script> +<meta name="quarto:offset" content="../"> +<link href="../favicon_png.png" rel="icon" type="image/png"> +<script src="../site_libs/quarto-html/quarto.js"></script> +<script src="../site_libs/quarto-html/popper.min.js"></script> +<script src="../site_libs/quarto-html/tippy.umd.min.js"></script> +<script src="../site_libs/quarto-html/anchor.min.js"></script> +<link href="../site_libs/quarto-html/tippy.css" rel="stylesheet"> +<link href="../site_libs/quarto-html/quarto-syntax-highlighting.css" rel="stylesheet" id="quarto-text-highlighting-styles"> +<script src="../site_libs/bootstrap/bootstrap.min.js"></script> +<link href="../site_libs/bootstrap/bootstrap-icons.css" rel="stylesheet"> +<link href="../site_libs/bootstrap/bootstrap.min.css" rel="stylesheet" id="quarto-bootstrap" data-mode="light"> +<script id="quarto-search-options" type="application/json">{ + "location": "navbar", + "copy-button": false, + "collapse-after": 3, + "panel-placement": "end", + "type": "overlay", + "limit": 20, + "language": { + "search-no-results-text": "No results", + "search-matching-documents-text": "matching documents", + "search-copy-link-title": "Copy link to search", + "search-hide-matches-text": "Hide additional matches", + "search-more-match-text": "more match in this document", + "search-more-matches-text": "more matches in this document", + "search-clear-button-title": "Clear", + "search-detached-cancel-button-title": "Cancel", + "search-submit-button-title": "Submit", + "search-label": "Search" + } +}</script> +<script async="" src="https://www.googletagmanager.com/gtag/js?id=G-NXJNCVR18L"></script> + +<script type="text/javascript"> + +window.dataLayer = window.dataLayer || []; +function gtag(){dataLayer.push(arguments);} +gtag('js', new Date()); +gtag('config', 'G-NXJNCVR18L', { 'anonymize_ip': true}); +</script> +<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js" integrity="sha512-c3Nl8+7g4LMSTdrm621y7kf9v3SDPnhxLNhcjFJbKECVnmZHTdo+IRO05sNLTH/D3vA6u1X32ehoLC7WFVdheg==" crossorigin="anonymous"></script> +<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js" integrity="sha512-bLT0Qm9VnAYZDflyKcBaQ2gg0hSYNQrJ8RilYldYQ1FxQYoCLtUjuuRuZo+fjqhx/qtq/1itJ0C2ejDxltZVFg==" crossorigin="anonymous"></script> +<script type="application/javascript">define('jquery', [],function() {return window.jQuery;})</script> + + +<link rel="stylesheet" href="../styles.css"> +<meta property="og:title" content="hierarchicalforecast - Non-Negative MinTrace"> +<meta property="og:description" content=""> +<meta property="og:image" content="https://colab.research.google.com/assets/colab-badge.svg"> +<meta property="og:site-name" content="hierarchicalforecast"> +<meta name="twitter:title" content="hierarchicalforecast - Non-Negative MinTrace"> +<meta name="twitter:description" content=""> +<meta name="twitter:image" content="https://colab.research.google.com/assets/colab-badge.svg"> +<meta name="twitter:card" content="summary_large_image"> +</head> + +<body class="nav-sidebar floating nav-fixed"> + +<div id="quarto-search-results"></div> + <header id="quarto-header" class="headroom fixed-top"> + <nav class="navbar navbar-expand-lg navbar-dark "> + <div class="navbar-container container-fluid"> + <div class="navbar-brand-container"> + <a class="navbar-brand" href="../index.html"> + <span class="navbar-title">hierarchicalforecast</span> + </a> + </div> + <div id="quarto-search" class="" title="Search"></div> + <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + <span class="navbar-toggler-icon"></span> +</button> + <div class="collapse navbar-collapse" id="navbarCollapse"> + <ul class="navbar-nav navbar-nav-scroll me-auto"> + <li class="nav-item"> + <a class="nav-link active" href="../examples/tourismsmall.html" rel="" target="" aria-current="page"> + <span class="menu-text">Get Started</span></a> + </li> + <li class="nav-item dropdown "> + <a class="nav-link dropdown-toggle" href="#" id="nav-menu-nixtlaverse" role="button" data-bs-toggle="dropdown" aria-expanded="false" rel="" target=""> + <span class="menu-text">NixtlaVerse</span> + </a> + <ul class="dropdown-menu" aria-labelledby="nav-menu-nixtlaverse"> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/mlforecast" rel="" target=""> + <span class="dropdown-text">MLForecast š¤</span></a> + </li> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/neuralforecast" rel="" target=""> + <span class="dropdown-text">NeuralForecast š§ </span></a> + </li> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/statsforecast" rel="" target=""> + <span class="dropdown-text">StatsForecast ā”ļø</span></a> + </li> + </ul> + </li> + <li class="nav-item dropdown "> + <a class="nav-link dropdown-toggle" href="#" id="nav-menu-help" role="button" data-bs-toggle="dropdown" aria-expanded="false" rel="" target=""> + <span class="menu-text">Help</span> + </a> + <ul class="dropdown-menu" aria-labelledby="nav-menu-help"> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/hierarchicalforecast/issues/new/choose" rel="" target=""><i class="bi bi-bug" role="img"> +</i> + <span class="dropdown-text">Report an Issue</span></a> + </li> + <li> + <a class="dropdown-item" href="https://join.slack.com/t/nixtlacommunity/shared_invite/zt-1kd5m5db7-7OOfy0xVNf1PcvCiAPWvPw" rel="" target=""><i class="bi bi-chat-right-text" role="img"> +</i> + <span class="dropdown-text">Join our Slack</span></a> + </li> + </ul> + </li> +</ul> + <ul class="navbar-nav navbar-nav-scroll ms-auto"> + <li class="nav-item compact"> + <a class="nav-link" href="https://github.com/nixtla/hierarchicalforecast" rel="" target=""><i class="bi bi-github" role="img"> +</i> + <span class="menu-text"></span></a> + </li> + <li class="nav-item compact"> + <a class="nav-link" href="https://twitter.com/nixtlainc" rel="" target=""><i class="bi bi-twitter" role="img" aria-label="Nixtla Twitter"> +</i> + <span class="menu-text"></span></a> + </li> +</ul> + <div class="quarto-navbar-tools"> +</div> + </div> <!-- /navcollapse --> + </div> <!-- /container-fluid --> + </nav> + <nav class="quarto-secondary-nav"> + <div class="container-fluid d-flex"> + <button type="button" class="quarto-btn-toggle btn" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + <i class="bi bi-layout-text-sidebar-reverse"></i> + </button> + <nav class="quarto-page-breadcrumbs" aria-label="breadcrumb"><ol class="breadcrumb"><li class="breadcrumb-item">Tutorials</li><li class="breadcrumb-item"><a href="../examples/australiandomestictourism.html">Point Reconciliation</a></li><li class="breadcrumb-item"><a href="../examples/nonnegativereconciliation.html">Non-Negative MinTrace</a></li></ol></nav> + <a class="flex-grow-1" role="button" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + </a> + </div> + </nav> +</header> +<!-- content --> +<div id="quarto-content" class="quarto-container page-columns page-rows-contents page-layout-article page-navbar"> +<!-- sidebar --> + <nav id="quarto-sidebar" class="sidebar collapse collapse-horizontal sidebar-navigation floating overflow-auto"> + <div class="sidebar-menu-container"> + <ul class="list-unstyled mt-1"> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../index.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Hierarchical Forecast š</span></a> + </div> +</li> + <li class="px-0"><hr class="sidebar-divider hi "></li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-1" aria-expanded="false"> + <span class="menu-text">Getting Started</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-1" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-1" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/installation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Install</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/tourismsmall.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Reconciliation Quick Start</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/introduction.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Introduction</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-2" aria-expanded="true"> + <span class="menu-text">Tutorials</span></a> + <a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-2" aria-expanded="true" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-2" class="collapse list-unstyled sidebar-section depth1 show"> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-3" aria-expanded="true"> + <span class="menu-text">Point Reconciliation</span></a> + <a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-3" aria-expanded="true" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-3" class="collapse list-unstyled sidebar-section depth2 show"> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Geographical Aggregation (Tourism)</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australianprisonpopulation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Geographical Aggregation (Prison Population)</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/nonnegativereconciliation.html" class="sidebar-item-text sidebar-link active"> + <span class="menu-text">Non-Negative MinTrace</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-4" aria-expanded="false"> + <span class="menu-text">Probabilistic Reconciliation</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-4" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-4" class="collapse list-unstyled sidebar-section depth2 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Normality</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism-bootstraped-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Bootstrap</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism-permbu-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">PERMBU</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/tourismlarge-evaluation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Probabilistic Forecast Evaluation</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-5" aria-expanded="false"> + <span class="menu-text">ML Forecast Reconciliation</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-5" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-5" class="collapse list-unstyled sidebar-section depth2 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/hierarchicalforecast-gluonts.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">GluonTS</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/mlframeworksexample.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Neural/MLForecast</span></a> + </div> +</li> + </ul> + </li> + </ul> + </li> + <li class="sidebar-item"> + <span class="menu-text">Methods</span> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-6" aria-expanded="false"> + <span class="menu-text">API Reference</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-6" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-6" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../core.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Core </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../methods.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Reconciliation Methods </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../probabilistic_methods.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Probabilistic Methods </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../evaluation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Hierarchical Evaluation</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../utils.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Aggregation/Visualization Utils</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-7" aria-expanded="false"> + <span class="menu-text">Community</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-7" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-7" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item"> + <span class="menu-text">Contributing</span> + </li> + </ul> + </li> + </ul> + </div> +</nav> +<div id="quarto-sidebar-glass" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass"></div> +<!-- margin-sidebar --> + <div id="quarto-margin-sidebar" class="sidebar margin-sidebar"> + <nav id="TOC" role="doc-toc" class="toc-active"> + <h2 id="toc-title">On this page</h2> + + <ul> + <li><a href="#load-data" id="toc-load-data" class="nav-link active" data-scroll-target="#load-data">1. Load Data</a></li> + <li><a href="#base-forecasts" id="toc-base-forecasts" class="nav-link" data-scroll-target="#base-forecasts">2. Base Forecasts</a></li> + <li><a href="#non-negative-reconciliation" id="toc-non-negative-reconciliation" class="nav-link" data-scroll-target="#non-negative-reconciliation">3. Non-Negative Reconciliation</a></li> + <li><a href="#evaluation" id="toc-evaluation" class="nav-link" data-scroll-target="#evaluation">4. Evaluation</a> + <ul class="collapse"> + <li><a href="#references" id="toc-references" class="nav-link" data-scroll-target="#references">References</a></li> + </ul></li> + </ul> +<div class="toc-actions"><div><i class="bi bi-github"></i></div><div class="action-links"><p><a href="https://github.com/Nixtla/hierarchicalforecast/issues/new" class="toc-action">Report an issue</a></p></div></div></nav> + </div> +<!-- main --> +<main class="content" id="quarto-document-content"> + +<header id="title-block-header" class="quarto-title-block default"> +<div class="quarto-title"> +<h1 class="title">Non-Negative MinTrace</h1> +</div> + + + +<div class="quarto-title-meta"> + + + + + </div> + + +</header> + +<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! --> +<p>Large collections of time series organized into structures at different aggregation levels often require their forecasts to follow their aggregation constraints and to be nonnegative, which poses the challenge of creating novel algorithms capable of coherent forecasts.</p> +<p>The <code>HierarchicalForecast</code> package provides a wide collection of Python implementations of hierarchical forecasting algorithms that follow nonnegative hierarchical reconciliation.</p> +<p>In this notebook, we will show how to use the <code>HierarchicalForecast</code> package to perform nonnegative reconciliation of forecasts on <code>Wiki2</code> dataset.</p> +<p>You can run these experiments using CPU or GPU with Google Colab.</p> +<p><a href="https://colab.research.google.com/github/Nixtla/hierarchicalforecast/blob/main/nbs/examples/NonNegativeReconciliation.ipynb" target="_parent"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"></a></p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb1"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="op">!</span>pip install hierarchicalforecast statsforecast datasetsforecast</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<section id="load-data" class="level2"> +<h2 class="anchored" data-anchor-id="load-data">1. Load Data</h2> +<p>In this example we will use the <code>Wiki2</code> dataset. The following cell gets the time series for the different levels in the hierarchy, the summing dataframe <code>S_df</code> which recovers the full dataset from the bottom level hierarchy and the indices of each hierarchy denoted by <code>tags</code>.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb2"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> numpy <span class="im">as</span> np</span> +<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> pandas <span class="im">as</span> pd</span> +<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> datasetsforecast.hierarchical <span class="im">import</span> HierarchicalData</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb3"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a>Y_df, S_df, tags <span class="op">=</span> HierarchicalData.load(<span class="st">'./data'</span>, <span class="st">'Wiki2'</span>)</span> +<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>Y_df[<span class="st">'ds'</span>] <span class="op">=</span> pd.to_datetime(Y_df[<span class="st">'ds'</span>])</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb4"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a>Y_df.head()</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<div> + + +<table class="dataframe table table-sm table-striped small" data-quarto-postprocess="true" data-border="1"> +<thead> +<tr class="header"> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th">unique_id</th> +<th data-quarto-table-cell-role="th">ds</th> +<th data-quarto-table-cell-role="th">y</th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td data-quarto-table-cell-role="th">0</td> +<td>Total</td> +<td>2016-01-01</td> +<td>156508</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">1</td> +<td>Total</td> +<td>2016-01-02</td> +<td>129902</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">2</td> +<td>Total</td> +<td>2016-01-03</td> +<td>138203</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">3</td> +<td>Total</td> +<td>2016-01-04</td> +<td>115017</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">4</td> +<td>Total</td> +<td>2016-01-05</td> +<td>126042</td> +</tr> +</tbody> +</table> + +</div> +</div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb5"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a>S_df.iloc[:<span class="dv">5</span>, :<span class="dv">5</span>]</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<div> + + +<table class="dataframe table table-sm table-striped small" data-quarto-postprocess="true" data-border="1"> +<thead> +<tr class="header"> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th">de_AAC_AAG_001</th> +<th data-quarto-table-cell-role="th">de_AAC_AAG_010</th> +<th data-quarto-table-cell-role="th">de_AAC_AAG_014</th> +<th data-quarto-table-cell-role="th">de_AAC_AAG_045</th> +<th data-quarto-table-cell-role="th">de_AAC_AAG_063</th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td data-quarto-table-cell-role="th">Total</td> +<td>1</td> +<td>1</td> +<td>1</td> +<td>1</td> +<td>1</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">de</td> +<td>1</td> +<td>1</td> +<td>1</td> +<td>1</td> +<td>1</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">en</td> +<td>0</td> +<td>0</td> +<td>0</td> +<td>0</td> +<td>0</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">fr</td> +<td>0</td> +<td>0</td> +<td>0</td> +<td>0</td> +<td>0</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">ja</td> +<td>0</td> +<td>0</td> +<td>0</td> +<td>0</td> +<td>0</td> +</tr> +</tbody> +</table> + +</div> +</div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb6"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a>tags</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<pre><code>{'Views': array(['Total'], dtype=object), + 'Views/Country': array(['de', 'en', 'fr', 'ja', 'ru', 'zh'], dtype=object), + 'Views/Country/Access': array(['de_AAC', 'de_DES', 'de_MOB', 'en_AAC', 'en_DES', 'en_MOB', + 'fr_AAC', 'fr_DES', 'fr_MOB', 'ja_AAC', 'ja_DES', 'ja_MOB', + 'ru_AAC', 'ru_DES', 'ru_MOB', 'zh_AAC', 'zh_DES', 'zh_MOB'], + dtype=object), + 'Views/Country/Access/Agent': array(['de_AAC_AAG', 'de_AAC_SPD', 'de_DES_AAG', 'de_MOB_AAG', + 'en_AAC_AAG', 'en_AAC_SPD', 'en_DES_AAG', 'en_MOB_AAG', + 'fr_AAC_AAG', 'fr_AAC_SPD', 'fr_DES_AAG', 'fr_MOB_AAG', + 'ja_AAC_AAG', 'ja_AAC_SPD', 'ja_DES_AAG', 'ja_MOB_AAG', + 'ru_AAC_AAG', 'ru_AAC_SPD', 'ru_DES_AAG', 'ru_MOB_AAG', + 'zh_AAC_AAG', 'zh_AAC_SPD', 'zh_DES_AAG', 'zh_MOB_AAG'], + dtype=object), + 'Views/Country/Access/Agent/Topic': array(['de_AAC_AAG_001', 'de_AAC_AAG_010', 'de_AAC_AAG_014', + 'de_AAC_AAG_045', 'de_AAC_AAG_063', 'de_AAC_AAG_100', + 'de_AAC_AAG_110', 'de_AAC_AAG_123', 'de_AAC_AAG_143', + 'de_AAC_SPD_012', 'de_AAC_SPD_074', 'de_AAC_SPD_080', + 'de_AAC_SPD_105', 'de_AAC_SPD_115', 'de_AAC_SPD_133', + 'de_DES_AAG_064', 'de_DES_AAG_116', 'de_DES_AAG_131', + 'de_MOB_AAG_015', 'de_MOB_AAG_020', 'de_MOB_AAG_032', + 'de_MOB_AAG_059', 'de_MOB_AAG_062', 'de_MOB_AAG_088', + 'de_MOB_AAG_095', 'de_MOB_AAG_109', 'de_MOB_AAG_122', + 'de_MOB_AAG_149', 'en_AAC_AAG_044', 'en_AAC_AAG_049', + 'en_AAC_AAG_075', 'en_AAC_AAG_114', 'en_AAC_AAG_119', + 'en_AAC_AAG_141', 'en_AAC_SPD_004', 'en_AAC_SPD_011', + 'en_AAC_SPD_026', 'en_AAC_SPD_048', 'en_AAC_SPD_067', + 'en_AAC_SPD_126', 'en_AAC_SPD_140', 'en_DES_AAG_016', + 'en_DES_AAG_024', 'en_DES_AAG_042', 'en_DES_AAG_069', + 'en_DES_AAG_082', 'en_DES_AAG_102', 'en_MOB_AAG_018', + 'en_MOB_AAG_022', 'en_MOB_AAG_101', 'en_MOB_AAG_124', + 'fr_AAC_AAG_029', 'fr_AAC_AAG_046', 'fr_AAC_AAG_070', + 'fr_AAC_AAG_087', 'fr_AAC_AAG_098', 'fr_AAC_AAG_104', + 'fr_AAC_AAG_111', 'fr_AAC_AAG_112', 'fr_AAC_AAG_142', + 'fr_AAC_SPD_025', 'fr_AAC_SPD_027', 'fr_AAC_SPD_035', + 'fr_AAC_SPD_077', 'fr_AAC_SPD_084', 'fr_AAC_SPD_097', + 'fr_AAC_SPD_130', 'fr_DES_AAG_023', 'fr_DES_AAG_043', + 'fr_DES_AAG_051', 'fr_DES_AAG_058', 'fr_DES_AAG_061', + 'fr_DES_AAG_091', 'fr_DES_AAG_093', 'fr_DES_AAG_094', + 'fr_DES_AAG_136', 'fr_MOB_AAG_006', 'fr_MOB_AAG_030', + 'fr_MOB_AAG_066', 'fr_MOB_AAG_117', 'fr_MOB_AAG_120', + 'fr_MOB_AAG_121', 'fr_MOB_AAG_135', 'fr_MOB_AAG_147', + 'ja_AAC_AAG_038', 'ja_AAC_AAG_047', 'ja_AAC_AAG_055', + 'ja_AAC_AAG_076', 'ja_AAC_AAG_099', 'ja_AAC_AAG_128', + 'ja_AAC_AAG_132', 'ja_AAC_AAG_134', 'ja_AAC_AAG_137', + 'ja_AAC_SPD_013', 'ja_AAC_SPD_034', 'ja_AAC_SPD_050', + 'ja_AAC_SPD_060', 'ja_AAC_SPD_078', 'ja_AAC_SPD_106', + 'ja_DES_AAG_079', 'ja_DES_AAG_081', 'ja_DES_AAG_113', + 'ja_MOB_AAG_065', 'ja_MOB_AAG_073', 'ja_MOB_AAG_092', + 'ja_MOB_AAG_127', 'ja_MOB_AAG_129', 'ja_MOB_AAG_144', + 'ru_AAC_AAG_008', 'ru_AAC_AAG_145', 'ru_AAC_AAG_146', + 'ru_AAC_SPD_000', 'ru_AAC_SPD_090', 'ru_AAC_SPD_148', + 'ru_DES_AAG_003', 'ru_DES_AAG_007', 'ru_DES_AAG_017', + 'ru_DES_AAG_041', 'ru_DES_AAG_071', 'ru_DES_AAG_072', + 'ru_MOB_AAG_002', 'ru_MOB_AAG_040', 'ru_MOB_AAG_083', + 'ru_MOB_AAG_086', 'ru_MOB_AAG_103', 'ru_MOB_AAG_107', + 'ru_MOB_AAG_118', 'ru_MOB_AAG_125', 'zh_AAC_AAG_021', + 'zh_AAC_AAG_033', 'zh_AAC_AAG_037', 'zh_AAC_AAG_052', + 'zh_AAC_AAG_057', 'zh_AAC_AAG_085', 'zh_AAC_AAG_108', + 'zh_AAC_SPD_039', 'zh_AAC_SPD_096', 'zh_DES_AAG_009', + 'zh_DES_AAG_019', 'zh_DES_AAG_053', 'zh_DES_AAG_054', + 'zh_DES_AAG_056', 'zh_DES_AAG_068', 'zh_DES_AAG_089', + 'zh_DES_AAG_139', 'zh_MOB_AAG_005', 'zh_MOB_AAG_028', + 'zh_MOB_AAG_031', 'zh_MOB_AAG_036', 'zh_MOB_AAG_138'], dtype=object)}</code></pre> +</div> +</div> +<p>We split the dataframe in train/test splits.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb8"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a>Y_test_df <span class="op">=</span> Y_df.groupby(<span class="st">'unique_id'</span>).tail(<span class="dv">7</span>)</span> +<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a>Y_train_df <span class="op">=</span> Y_df.drop(Y_test_df.index)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb9"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a>Y_test_df <span class="op">=</span> Y_test_df.set_index(<span class="st">'unique_id'</span>)</span> +<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>Y_train_df <span class="op">=</span> Y_train_df.set_index(<span class="st">'unique_id'</span>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +</section> +<section id="base-forecasts" class="level2"> +<h2 class="anchored" data-anchor-id="base-forecasts">2. Base Forecasts</h2> +<p>The following cell computes the <em>base forecast</em> for each time series using the <code>ETS</code> and <code>naive</code> models. Observe that <code>Y_hat_df</code> contains the forecasts but they are not coherent.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb10"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> statsforecast.models <span class="im">import</span> ETS, Naive</span> +<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> statsforecast.core <span class="im">import</span> StatsForecast</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb11"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a>fcst <span class="op">=</span> StatsForecast(</span> +<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a> df<span class="op">=</span>Y_train_df, </span> +<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a> models<span class="op">=</span>[ETS(season_length<span class="op">=</span><span class="dv">7</span>, model<span class="op">=</span><span class="st">'ZAA'</span>), Naive()], </span> +<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a> freq<span class="op">=</span><span class="st">'D'</span>, </span> +<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a> n_jobs<span class="op">=-</span><span class="dv">1</span></span> +<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a>)</span> +<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a>Y_hat_df <span class="op">=</span> fcst.forecast(h<span class="op">=</span><span class="dv">7</span>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<p>Observe that the ETS model computes negative forecasts for some series.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb12"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a>Y_hat_df.query(<span class="st">'ETS < 0'</span>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<div> + + +<table class="dataframe table table-sm table-striped small" data-quarto-postprocess="true" data-border="1"> +<thead> +<tr class="header"> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th">ds</th> +<th data-quarto-table-cell-role="th">ETS</th> +<th data-quarto-table-cell-role="th">Naive</th> +</tr> +<tr class="odd"> +<th data-quarto-table-cell-role="th">unique_id</th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td data-quarto-table-cell-role="th">de_AAC_AAG_001</td> +<td>2016-12-25</td> +<td>-487.601532</td> +<td>340.0</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">de_AAC_AAG_001</td> +<td>2016-12-26</td> +<td>-215.634201</td> +<td>340.0</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">de_AAC_AAG_001</td> +<td>2016-12-27</td> +<td>-173.175613</td> +<td>340.0</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">de_AAC_AAG_001</td> +<td>2016-12-30</td> +<td>-290.836060</td> +<td>340.0</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">de_AAC_AAG_001</td> +<td>2016-12-31</td> +<td>-784.441040</td> +<td>340.0</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">...</td> +<td>...</td> +<td>...</td> +<td>...</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">zh_AAC_AAG_033</td> +<td>2016-12-31</td> +<td>-86.526421</td> +<td>37.0</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">zh_MOB</td> +<td>2016-12-26</td> +<td>-199.534882</td> +<td>1036.0</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">zh_MOB</td> +<td>2016-12-27</td> +<td>-69.527260</td> +<td>1036.0</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">zh_MOB_AAG</td> +<td>2016-12-26</td> +<td>-199.534882</td> +<td>1036.0</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">zh_MOB_AAG</td> +<td>2016-12-27</td> +<td>-69.527260</td> +<td>1036.0</td> +</tr> +</tbody> +</table> + +<p>99 rows Ć 3 columns</p> +</div> +</div> +</div> +</section> +<section id="non-negative-reconciliation" class="level2"> +<h2 class="anchored" data-anchor-id="non-negative-reconciliation">3. Non-Negative Reconciliation</h2> +<p>The following cell makes the previous forecasts coherent and nonnegative using the <a href="https://Nixtla.github.io/hierarchicalforecast/core.html#hierarchicalreconciliation"><code>HierarchicalReconciliation</code></a> class.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb13"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> hierarchicalforecast.methods <span class="im">import</span> MinTrace</span> +<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> hierarchicalforecast.core <span class="im">import</span> HierarchicalReconciliation</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb14"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a>reconcilers <span class="op">=</span> [</span> +<span id="cb14-2"><a href="#cb14-2" aria-hidden="true" tabindex="-1"></a> MinTrace(method<span class="op">=</span><span class="st">'ols'</span>),</span> +<span id="cb14-3"><a href="#cb14-3" aria-hidden="true" tabindex="-1"></a> MinTrace(method<span class="op">=</span><span class="st">'ols'</span>, nonnegative<span class="op">=</span><span class="va">True</span>)</span> +<span id="cb14-4"><a href="#cb14-4" aria-hidden="true" tabindex="-1"></a>]</span> +<span id="cb14-5"><a href="#cb14-5" aria-hidden="true" tabindex="-1"></a>hrec <span class="op">=</span> HierarchicalReconciliation(reconcilers<span class="op">=</span>reconcilers)</span> +<span id="cb14-6"><a href="#cb14-6" aria-hidden="true" tabindex="-1"></a>Y_rec_df <span class="op">=</span> hrec.reconcile(Y_hat_df<span class="op">=</span>Y_hat_df, Y_df<span class="op">=</span>Y_train_df,</span> +<span id="cb14-7"><a href="#cb14-7" aria-hidden="true" tabindex="-1"></a> S<span class="op">=</span>S_df, tags<span class="op">=</span>tags)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<p>Observe that the nonnegative reconciliation method obtains nonnegative forecasts.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb15"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a>Y_rec_df.query(<span class="st">'`ETS/MinTrace_method-ols_nonnegative-True` < 0'</span>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<div> + + +<table class="dataframe table table-sm table-striped small" data-quarto-postprocess="true" data-border="1"> +<thead> +<tr class="header"> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th">ds</th> +<th data-quarto-table-cell-role="th">ETS</th> +<th data-quarto-table-cell-role="th">Naive</th> +<th data-quarto-table-cell-role="th">ETS/MinTrace_method-ols</th> +<th data-quarto-table-cell-role="th">Naive/MinTrace_method-ols</th> +<th data-quarto-table-cell-role="th">ETS/MinTrace_method-ols_nonnegative-True</th> +<th data-quarto-table-cell-role="th">Naive/MinTrace_method-ols_nonnegative-True</th> +</tr> +<tr class="odd"> +<th data-quarto-table-cell-role="th">unique_id</th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +</tr> +</thead> +<tbody> +</tbody> +</table> + +</div> +</div> +</div> +<p>The free reconciliation method gets negative forecasts.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb16"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb16-1"><a href="#cb16-1" aria-hidden="true" tabindex="-1"></a>Y_rec_df.query(<span class="st">'`ETS/MinTrace_method-ols` < 0'</span>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<div> + + +<table class="dataframe table table-sm table-striped small" data-quarto-postprocess="true" data-border="1"> +<thead> +<tr class="header"> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th">ds</th> +<th data-quarto-table-cell-role="th">ETS</th> +<th data-quarto-table-cell-role="th">Naive</th> +<th data-quarto-table-cell-role="th">ETS/MinTrace_method-ols</th> +<th data-quarto-table-cell-role="th">Naive/MinTrace_method-ols</th> +<th data-quarto-table-cell-role="th">ETS/MinTrace_method-ols_nonnegative-True</th> +<th data-quarto-table-cell-role="th">Naive/MinTrace_method-ols_nonnegative-True</th> +</tr> +<tr class="odd"> +<th data-quarto-table-cell-role="th">unique_id</th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td data-quarto-table-cell-role="th">de_DES</td> +<td>2016-12-25</td> +<td>-2553.932861</td> +<td>495.0</td> +<td>-3468.745214</td> +<td>495.0</td> +<td>2.262540e-15</td> +<td>495.0</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">de_DES</td> +<td>2016-12-26</td> +<td>-2155.228271</td> +<td>495.0</td> +<td>-2985.587125</td> +<td>495.0</td> +<td>1.356705e-30</td> +<td>495.0</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">de_DES</td> +<td>2016-12-27</td> +<td>-2720.993896</td> +<td>495.0</td> +<td>-3698.680055</td> +<td>495.0</td> +<td>6.857413e-30</td> +<td>495.0</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">de_DES</td> +<td>2016-12-29</td> +<td>-3429.432617</td> +<td>495.0</td> +<td>-2965.207609</td> +<td>495.0</td> +<td>2.456449e+02</td> +<td>495.0</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">de_DES</td> +<td>2016-12-30</td> +<td>-3963.202637</td> +<td>495.0</td> +<td>-3217.360371</td> +<td>495.0</td> +<td>3.646790e+02</td> +<td>495.0</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">zh_MOB_AAG_036</td> +<td>2016-12-26</td> +<td>75.298317</td> +<td>115.0</td> +<td>-165.799776</td> +<td>115.0</td> +<td>3.207772e-14</td> +<td>115.0</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">zh_MOB_AAG_036</td> +<td>2016-12-27</td> +<td>72.895554</td> +<td>115.0</td> +<td>-134.340626</td> +<td>115.0</td> +<td>2.308198e-14</td> +<td>115.0</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">zh_MOB_AAG_138</td> +<td>2016-12-25</td> +<td>94.796623</td> +<td>65.0</td> +<td>-47.009813</td> +<td>65.0</td> +<td>3.116938e-14</td> +<td>65.0</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">zh_MOB_AAG_138</td> +<td>2016-12-26</td> +<td>71.293983</td> +<td>65.0</td> +<td>-169.804110</td> +<td>65.0</td> +<td>0.000000e+00</td> +<td>65.0</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">zh_MOB_AAG_138</td> +<td>2016-12-27</td> +<td>62.049744</td> +<td>65.0</td> +<td>-145.186436</td> +<td>65.0</td> +<td>0.000000e+00</td> +<td>65.0</td> +</tr> +</tbody> +</table> + +<p>240 rows Ć 7 columns</p> +</div> +</div> +</div> +</section> +<section id="evaluation" class="level2"> +<h2 class="anchored" data-anchor-id="evaluation">4. Evaluation</h2> +<p>The <code>HierarchicalForecast</code> package includes the <a href="https://Nixtla.github.io/hierarchicalforecast/evaluation.html#hierarchicalevaluation"><code>HierarchicalEvaluation</code></a> class to evaluate the different hierarchies and also is capable of compute scaled metrics compared to a benchmark model.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb17"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> hierarchicalforecast.evaluation <span class="im">import</span> HierarchicalEvaluation</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb18"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> mse(y, y_hat):</span> +<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> np.mean((y<span class="op">-</span>y_hat)<span class="op">**</span><span class="dv">2</span>)</span> +<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb18-4"><a href="#cb18-4" aria-hidden="true" tabindex="-1"></a>evaluator <span class="op">=</span> HierarchicalEvaluation(evaluators<span class="op">=</span>[mse])</span> +<span id="cb18-5"><a href="#cb18-5" aria-hidden="true" tabindex="-1"></a>evaluation <span class="op">=</span> evaluator.evaluate(</span> +<span id="cb18-6"><a href="#cb18-6" aria-hidden="true" tabindex="-1"></a> Y_hat_df<span class="op">=</span>Y_rec_df, Y_test_df<span class="op">=</span>Y_test_df, </span> +<span id="cb18-7"><a href="#cb18-7" aria-hidden="true" tabindex="-1"></a> tags<span class="op">=</span>tags, benchmark<span class="op">=</span><span class="st">'Naive'</span></span> +<span id="cb18-8"><a href="#cb18-8" aria-hidden="true" tabindex="-1"></a>)</span> +<span id="cb18-9"><a href="#cb18-9" aria-hidden="true" tabindex="-1"></a>evaluation.<span class="bu">filter</span>(like<span class="op">=</span><span class="st">'ETS'</span>, axis<span class="op">=</span><span class="dv">1</span>).T</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<div> + + +<table class="dataframe table table-sm table-striped small" data-quarto-postprocess="true" data-border="1"> +<thead> +<tr class="header"> +<th data-quarto-table-cell-role="th">level</th> +<th data-quarto-table-cell-role="th">Overall</th> +<th data-quarto-table-cell-role="th">Views</th> +<th data-quarto-table-cell-role="th">Views/Country</th> +<th data-quarto-table-cell-role="th">Views/Country/Access</th> +<th data-quarto-table-cell-role="th">Views/Country/Access/Agent</th> +<th data-quarto-table-cell-role="th">Views/Country/Access/Agent/Topic</th> +</tr> +<tr class="odd"> +<th data-quarto-table-cell-role="th">metric</th> +<th data-quarto-table-cell-role="th">mse-scaled</th> +<th data-quarto-table-cell-role="th">mse-scaled</th> +<th data-quarto-table-cell-role="th">mse-scaled</th> +<th data-quarto-table-cell-role="th">mse-scaled</th> +<th data-quarto-table-cell-role="th">mse-scaled</th> +<th data-quarto-table-cell-role="th">mse-scaled</th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td data-quarto-table-cell-role="th">ETS</td> +<td>1.011585</td> +<td>0.7358</td> +<td>1.190354</td> +<td>1.103657</td> +<td>1.089515</td> +<td>1.397139</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">ETS/MinTrace_method-ols</td> +<td>0.979163</td> +<td>0.698355</td> +<td>1.062521</td> +<td>1.143277</td> +<td>1.113349</td> +<td>1.354041</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">ETS/MinTrace_method-ols_nonnegative-True</td> +<td>0.945075</td> +<td>0.677892</td> +<td>1.004639</td> +<td>1.184719</td> +<td>1.141442</td> +<td>1.158672</td> +</tr> +</tbody> +</table> + +</div> +</div> +</div> +<p>Observe that the nonnegative reconciliation method performs better that its unconstrained counterpart.</p> +<section id="references" class="level3"> +<h3 class="anchored" data-anchor-id="references">References</h3> +<ul> +<li><a href="https://otexts.com/fpp3/hierarchical.html">Hyndman, R.J., & Athanasopoulos, G. (2021). āForecasting: principles and practice, 3rd edition: Chapter 11: Forecasting hierarchical and grouped series.ā. OTexts: Melbourne, Australia. OTexts.com/fpp3 Accessed on July 2022.</a></li> +<li><a href="https://robjhyndman.com/publications/mint/">Wickramasuriya, S. L., Athanasopoulos, G., & Hyndman, R. J. (2019). "Optimal forecast reconciliation for hierarchical and grouped time series through trace minimization". Journal of the American Statistical Association, 114 , 804ā819. doi:10.1080/01621459.2018.1448825.</a>.</li> +<li><a href="https://robjhyndman.com/publications/nnmint/">Wickramasuriya, S.L., Turlach, B.A. & Hyndman, R.J. (2020). "Optimal non-negative forecast reconciliationā. Stat Comput 30, 1167ā1182, https://doi.org/10.1007/s11222-020-09930-0</a>.</li> +</ul> + + +</section> +</section> + +<p>If you find the code useful, please ā us on <a href="https://github.com/nixtla/hierarchicalforecast">Github</a></p></main> <!-- /main --> +<script id="quarto-html-after-body" type="application/javascript"> +window.document.addEventListener("DOMContentLoaded", function (event) { + const toggleBodyColorMode = (bsSheetEl) => { + const mode = bsSheetEl.getAttribute("data-mode"); + const bodyEl = window.document.querySelector("body"); + if (mode === "dark") { + bodyEl.classList.add("quarto-dark"); + bodyEl.classList.remove("quarto-light"); + } else { + bodyEl.classList.add("quarto-light"); + bodyEl.classList.remove("quarto-dark"); + } + } + const toggleBodyColorPrimary = () => { + const bsSheetEl = window.document.querySelector("link#quarto-bootstrap"); + if (bsSheetEl) { + toggleBodyColorMode(bsSheetEl); + } + } + toggleBodyColorPrimary(); + const icon = "ī§"; + const anchorJS = new window.AnchorJS(); + anchorJS.options = { + placement: 'right', + icon: icon + }; + anchorJS.add('.anchored'); + const isCodeAnnotation = (el) => { + for (const clz of el.classList) { + if (clz.startsWith('code-annotation-')) { + return true; + } + } + return false; + } + const clipboard = new window.ClipboardJS('.code-copy-button', { + text: function(trigger) { + const codeEl = trigger.previousElementSibling.cloneNode(true); + for (const childEl of codeEl.children) { + if (isCodeAnnotation(childEl)) { + childEl.remove(); + } + } + return codeEl.innerText; + } + }); + clipboard.on('success', function(e) { + // button target + const button = e.trigger; + // don't keep focus + button.blur(); + // flash "checked" + button.classList.add('code-copy-button-checked'); + var currentTitle = button.getAttribute("title"); + button.setAttribute("title", "Copied!"); + let tooltip; + if (window.bootstrap) { + button.setAttribute("data-bs-toggle", "tooltip"); + button.setAttribute("data-bs-placement", "left"); + button.setAttribute("data-bs-title", "Copied!"); + tooltip = new bootstrap.Tooltip(button, + { trigger: "manual", + customClass: "code-copy-button-tooltip", + offset: [0, -8]}); + tooltip.show(); + } + setTimeout(function() { + if (tooltip) { + tooltip.hide(); + button.removeAttribute("data-bs-title"); + button.removeAttribute("data-bs-toggle"); + button.removeAttribute("data-bs-placement"); + } + button.setAttribute("title", currentTitle); + button.classList.remove('code-copy-button-checked'); + }, 1000); + // clear code selection + e.clearSelection(); + }); + function tippyHover(el, contentFn) { + const config = { + allowHTML: true, + content: contentFn, + maxWidth: 500, + delay: 100, + arrow: false, + appendTo: function(el) { + return el.parentElement; + }, + interactive: true, + interactiveBorder: 10, + theme: 'quarto', + placement: 'bottom-start' + }; + window.tippy(el, config); + } + const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]'); + for (var i=0; i<noterefs.length; i++) { + const ref = noterefs[i]; + tippyHover(ref, function() { + // use id or data attribute instead here + let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href'); + try { href = new URL(href).hash; } catch {} + const id = href.replace(/^#\/?/, ""); + const note = window.document.getElementById(id); + return note.innerHTML; + }); + } + let selectedAnnoteEl; + const selectorForAnnotation = ( cell, annotation) => { + let cellAttr = 'data-code-cell="' + cell + '"'; + let lineAttr = 'data-code-annotation="' + annotation + '"'; + const selector = 'span[' + cellAttr + '][' + lineAttr + ']'; + return selector; + } + const selectCodeLines = (annoteEl) => { + const doc = window.document; + const targetCell = annoteEl.getAttribute("data-target-cell"); + const targetAnnotation = annoteEl.getAttribute("data-target-annotation"); + const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation)); + const lines = annoteSpan.getAttribute("data-code-lines").split(","); + const lineIds = lines.map((line) => { + return targetCell + "-" + line; + }) + let top = null; + let height = null; + let parent = null; + if (lineIds.length > 0) { + //compute the position of the single el (top and bottom and make a div) + const el = window.document.getElementById(lineIds[0]); + top = el.offsetTop; + height = el.offsetHeight; + parent = el.parentElement.parentElement; + if (lineIds.length > 1) { + const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]); + const bottom = lastEl.offsetTop + lastEl.offsetHeight; + height = bottom - top; + } + if (top !== null && height !== null && parent !== null) { + // cook up a div (if necessary) and position it + let div = window.document.getElementById("code-annotation-line-highlight"); + if (div === null) { + div = window.document.createElement("div"); + div.setAttribute("id", "code-annotation-line-highlight"); + div.style.position = 'absolute'; + parent.appendChild(div); + } + div.style.top = top - 2 + "px"; + div.style.height = height + 4 + "px"; + let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter"); + if (gutterDiv === null) { + gutterDiv = window.document.createElement("div"); + gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter"); + gutterDiv.style.position = 'absolute'; + const codeCell = window.document.getElementById(targetCell); + const gutter = codeCell.querySelector('.code-annotation-gutter'); + gutter.appendChild(gutterDiv); + } + gutterDiv.style.top = top - 2 + "px"; + gutterDiv.style.height = height + 4 + "px"; + } + selectedAnnoteEl = annoteEl; + } + }; + const unselectCodeLines = () => { + const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"]; + elementsIds.forEach((elId) => { + const div = window.document.getElementById(elId); + if (div) { + div.remove(); + } + }); + selectedAnnoteEl = undefined; + }; + // Attach click handler to the DT + const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); + for (const annoteDlNode of annoteDls) { + annoteDlNode.addEventListener('click', (event) => { + const clickedEl = event.target; + if (clickedEl !== selectedAnnoteEl) { + unselectCodeLines(); + const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active'); + if (activeEl) { + activeEl.classList.remove('code-annotation-active'); + } + selectCodeLines(clickedEl); + clickedEl.classList.add('code-annotation-active'); + } else { + // Unselect the line + unselectCodeLines(); + clickedEl.classList.remove('code-annotation-active'); + } + }); + } + const findCites = (el) => { + const parentEl = el.parentElement; + if (parentEl) { + const cites = parentEl.dataset.cites; + if (cites) { + return { + el, + cites: cites.split(' ') + }; + } else { + return findCites(el.parentElement) + } + } else { + return undefined; + } + }; + var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]'); + for (var i=0; i<bibliorefs.length; i++) { + const ref = bibliorefs[i]; + const citeInfo = findCites(ref); + if (citeInfo) { + tippyHover(citeInfo.el, function() { + var popup = window.document.createElement('div'); + citeInfo.cites.forEach(function(cite) { + var citeDiv = window.document.createElement('div'); + citeDiv.classList.add('hanging-indent'); + citeDiv.classList.add('csl-entry'); + var biblioDiv = window.document.getElementById('ref-' + cite); + if (biblioDiv) { + citeDiv.innerHTML = biblioDiv.innerHTML; + } + popup.appendChild(citeDiv); + }); + return popup.innerHTML; + }); + } + } +}); +</script> +</div> <!-- /content --> + + + +</body></html> \ No newline at end of file diff --git a/examples/tourismlarge-evaluation.html b/examples/tourismlarge-evaluation.html new file mode 100644 index 00000000..52ea3237 --- /dev/null +++ b/examples/tourismlarge-evaluation.html @@ -0,0 +1,2305 @@ +<!DOCTYPE html> +<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head> + +<meta charset="utf-8"> +<meta name="generator" content="quarto-1.3.450"> + +<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes"> + +<meta name="description" content="Hierarchical Forecastās reconciliation and evaluation."> + +<title>hierarchicalforecast - Probabilistic Forecast Evaluation</title> +<style> +code{white-space: pre-wrap;} +span.smallcaps{font-variant: small-caps;} +div.columns{display: flex; gap: min(4vw, 1.5em);} +div.column{flex: auto; overflow-x: auto;} +div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;} +ul.task-list{list-style: none;} +ul.task-list li input[type="checkbox"] { + width: 0.8em; + margin: 0 0.8em 0.2em -1em; /* quarto-specific, see https://github.com/quarto-dev/quarto-cli/issues/4556 */ + vertical-align: middle; +} +/* CSS for syntax highlighting */ +pre > code.sourceCode { white-space: pre; position: relative; } +pre > code.sourceCode > span { display: inline-block; line-height: 1.25; } +pre > code.sourceCode > span:empty { height: 1.2em; } +.sourceCode { overflow: visible; } +code.sourceCode > span { color: inherit; text-decoration: inherit; } +div.sourceCode { margin: 1em 0; } +pre.sourceCode { margin: 0; } +@media screen { +div.sourceCode { overflow: auto; } +} +@media print { +pre > code.sourceCode { white-space: pre-wrap; } +pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; } +} +pre.numberSource code + { counter-reset: source-line 0; } +pre.numberSource code > span + { position: relative; left: -4em; counter-increment: source-line; } +pre.numberSource code > span > a:first-child::before + { content: counter(source-line); + position: relative; left: -1em; text-align: right; vertical-align: baseline; + border: none; display: inline-block; + -webkit-touch-callout: none; -webkit-user-select: none; + -khtml-user-select: none; -moz-user-select: none; + -ms-user-select: none; user-select: none; + padding: 0 4px; width: 4em; + } +pre.numberSource { margin-left: 3em; padding-left: 4px; } +div.sourceCode + { } +@media screen { +pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; } +} +</style> + + +<script src="../site_libs/quarto-nav/quarto-nav.js"></script> +<script src="../site_libs/quarto-nav/headroom.min.js"></script> +<script src="../site_libs/clipboard/clipboard.min.js"></script> +<script src="../site_libs/quarto-search/autocomplete.umd.js"></script> +<script src="../site_libs/quarto-search/fuse.min.js"></script> +<script src="../site_libs/quarto-search/quarto-search.js"></script> +<meta name="quarto:offset" content="../"> +<link href="../favicon_png.png" rel="icon" type="image/png"> +<script src="../site_libs/quarto-html/quarto.js"></script> +<script src="../site_libs/quarto-html/popper.min.js"></script> +<script src="../site_libs/quarto-html/tippy.umd.min.js"></script> +<script src="../site_libs/quarto-html/anchor.min.js"></script> +<link href="../site_libs/quarto-html/tippy.css" rel="stylesheet"> +<link href="../site_libs/quarto-html/quarto-syntax-highlighting.css" rel="stylesheet" id="quarto-text-highlighting-styles"> +<script src="../site_libs/bootstrap/bootstrap.min.js"></script> +<link href="../site_libs/bootstrap/bootstrap-icons.css" rel="stylesheet"> +<link href="../site_libs/bootstrap/bootstrap.min.css" rel="stylesheet" id="quarto-bootstrap" data-mode="light"> +<script id="quarto-search-options" type="application/json">{ + "location": "navbar", + "copy-button": false, + "collapse-after": 3, + "panel-placement": "end", + "type": "overlay", + "limit": 20, + "language": { + "search-no-results-text": "No results", + "search-matching-documents-text": "matching documents", + "search-copy-link-title": "Copy link to search", + "search-hide-matches-text": "Hide additional matches", + "search-more-match-text": "more match in this document", + "search-more-matches-text": "more matches in this document", + "search-clear-button-title": "Clear", + "search-detached-cancel-button-title": "Cancel", + "search-submit-button-title": "Submit", + "search-label": "Search" + } +}</script> +<script async="" src="https://www.googletagmanager.com/gtag/js?id=G-NXJNCVR18L"></script> + +<script type="text/javascript"> + +window.dataLayer = window.dataLayer || []; +function gtag(){dataLayer.push(arguments);} +gtag('js', new Date()); +gtag('config', 'G-NXJNCVR18L', { 'anonymize_ip': true}); +</script> +<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js" integrity="sha512-c3Nl8+7g4LMSTdrm621y7kf9v3SDPnhxLNhcjFJbKECVnmZHTdo+IRO05sNLTH/D3vA6u1X32ehoLC7WFVdheg==" crossorigin="anonymous"></script> +<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js" integrity="sha512-bLT0Qm9VnAYZDflyKcBaQ2gg0hSYNQrJ8RilYldYQ1FxQYoCLtUjuuRuZo+fjqhx/qtq/1itJ0C2ejDxltZVFg==" crossorigin="anonymous"></script> +<script type="application/javascript">define('jquery', [],function() {return window.jQuery;})</script> + + +<link rel="stylesheet" href="../styles.css"> +<meta property="og:title" content="hierarchicalforecast - Probabilistic Forecast Evaluation"> +<meta property="og:description" content="Hierarchical Forecastās reconciliation and evaluation."> +<meta property="og:image" content="https://colab.research.google.com/assets/colab-badge.svg"> +<meta property="og:site-name" content="hierarchicalforecast"> +<meta name="twitter:title" content="hierarchicalforecast - Probabilistic Forecast Evaluation"> +<meta name="twitter:description" content="Hierarchical Forecastās reconciliation and evaluation."> +<meta name="twitter:image" content="https://colab.research.google.com/assets/colab-badge.svg"> +<meta name="twitter:card" content="summary_large_image"> +</head> + +<body class="nav-sidebar floating nav-fixed"> + +<div id="quarto-search-results"></div> + <header id="quarto-header" class="headroom fixed-top"> + <nav class="navbar navbar-expand-lg navbar-dark "> + <div class="navbar-container container-fluid"> + <div class="navbar-brand-container"> + <a class="navbar-brand" href="../index.html"> + <span class="navbar-title">hierarchicalforecast</span> + </a> + </div> + <div id="quarto-search" class="" title="Search"></div> + <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + <span class="navbar-toggler-icon"></span> +</button> + <div class="collapse navbar-collapse" id="navbarCollapse"> + <ul class="navbar-nav navbar-nav-scroll me-auto"> + <li class="nav-item"> + <a class="nav-link active" href="../examples/tourismsmall.html" rel="" target="" aria-current="page"> + <span class="menu-text">Get Started</span></a> + </li> + <li class="nav-item dropdown "> + <a class="nav-link dropdown-toggle" href="#" id="nav-menu-nixtlaverse" role="button" data-bs-toggle="dropdown" aria-expanded="false" rel="" target=""> + <span class="menu-text">NixtlaVerse</span> + </a> + <ul class="dropdown-menu" aria-labelledby="nav-menu-nixtlaverse"> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/mlforecast" rel="" target=""> + <span class="dropdown-text">MLForecast š¤</span></a> + </li> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/neuralforecast" rel="" target=""> + <span class="dropdown-text">NeuralForecast š§ </span></a> + </li> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/statsforecast" rel="" target=""> + <span class="dropdown-text">StatsForecast ā”ļø</span></a> + </li> + </ul> + </li> + <li class="nav-item dropdown "> + <a class="nav-link dropdown-toggle" href="#" id="nav-menu-help" role="button" data-bs-toggle="dropdown" aria-expanded="false" rel="" target=""> + <span class="menu-text">Help</span> + </a> + <ul class="dropdown-menu" aria-labelledby="nav-menu-help"> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/hierarchicalforecast/issues/new/choose" rel="" target=""><i class="bi bi-bug" role="img"> +</i> + <span class="dropdown-text">Report an Issue</span></a> + </li> + <li> + <a class="dropdown-item" href="https://join.slack.com/t/nixtlacommunity/shared_invite/zt-1kd5m5db7-7OOfy0xVNf1PcvCiAPWvPw" rel="" target=""><i class="bi bi-chat-right-text" role="img"> +</i> + <span class="dropdown-text">Join our Slack</span></a> + </li> + </ul> + </li> +</ul> + <ul class="navbar-nav navbar-nav-scroll ms-auto"> + <li class="nav-item compact"> + <a class="nav-link" href="https://github.com/nixtla/hierarchicalforecast" rel="" target=""><i class="bi bi-github" role="img"> +</i> + <span class="menu-text"></span></a> + </li> + <li class="nav-item compact"> + <a class="nav-link" href="https://twitter.com/nixtlainc" rel="" target=""><i class="bi bi-twitter" role="img" aria-label="Nixtla Twitter"> +</i> + <span class="menu-text"></span></a> + </li> +</ul> + <div class="quarto-navbar-tools"> +</div> + </div> <!-- /navcollapse --> + </div> <!-- /container-fluid --> + </nav> + <nav class="quarto-secondary-nav"> + <div class="container-fluid d-flex"> + <button type="button" class="quarto-btn-toggle btn" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + <i class="bi bi-layout-text-sidebar-reverse"></i> + </button> + <nav class="quarto-page-breadcrumbs" aria-label="breadcrumb"><ol class="breadcrumb"><li class="breadcrumb-item">Tutorials</li><li class="breadcrumb-item"><a href="../examples/australiandomestictourism-intervals.html">Probabilistic Reconciliation</a></li><li class="breadcrumb-item"><a href="../examples/tourismlarge-evaluation.html">Probabilistic Forecast Evaluation</a></li></ol></nav> + <a class="flex-grow-1" role="button" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + </a> + </div> + </nav> +</header> +<!-- content --> +<div id="quarto-content" class="quarto-container page-columns page-rows-contents page-layout-article page-navbar"> +<!-- sidebar --> + <nav id="quarto-sidebar" class="sidebar collapse collapse-horizontal sidebar-navigation floating overflow-auto"> + <div class="sidebar-menu-container"> + <ul class="list-unstyled mt-1"> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../index.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Hierarchical Forecast š</span></a> + </div> +</li> + <li class="px-0"><hr class="sidebar-divider hi "></li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-1" aria-expanded="false"> + <span class="menu-text">Getting Started</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-1" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-1" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/installation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Install</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/tourismsmall.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Reconciliation Quick Start</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/introduction.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Introduction</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-2" aria-expanded="true"> + <span class="menu-text">Tutorials</span></a> + <a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-2" aria-expanded="true" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-2" class="collapse list-unstyled sidebar-section depth1 show"> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-3" aria-expanded="false"> + <span class="menu-text">Point Reconciliation</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-3" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-3" class="collapse list-unstyled sidebar-section depth2 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Geographical Aggregation (Tourism)</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australianprisonpopulation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Geographical Aggregation (Prison Population)</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/nonnegativereconciliation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Non-Negative MinTrace</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-4" aria-expanded="true"> + <span class="menu-text">Probabilistic Reconciliation</span></a> + <a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-4" aria-expanded="true" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-4" class="collapse list-unstyled sidebar-section depth2 show"> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Normality</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism-bootstraped-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Bootstrap</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism-permbu-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">PERMBU</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/tourismlarge-evaluation.html" class="sidebar-item-text sidebar-link active"> + <span class="menu-text">Probabilistic Forecast Evaluation</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-5" aria-expanded="false"> + <span class="menu-text">ML Forecast Reconciliation</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-5" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-5" class="collapse list-unstyled sidebar-section depth2 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/hierarchicalforecast-gluonts.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">GluonTS</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/mlframeworksexample.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Neural/MLForecast</span></a> + </div> +</li> + </ul> + </li> + </ul> + </li> + <li class="sidebar-item"> + <span class="menu-text">Methods</span> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-6" aria-expanded="false"> + <span class="menu-text">API Reference</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-6" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-6" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../core.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Core </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../methods.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Reconciliation Methods </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../probabilistic_methods.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Probabilistic Methods </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../evaluation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Hierarchical Evaluation</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../utils.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Aggregation/Visualization Utils</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-7" aria-expanded="false"> + <span class="menu-text">Community</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-7" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-7" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item"> + <span class="menu-text">Contributing</span> + </li> + </ul> + </li> + </ul> + </div> +</nav> +<div id="quarto-sidebar-glass" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass"></div> +<!-- margin-sidebar --> + <div id="quarto-margin-sidebar" class="sidebar margin-sidebar"> + <nav id="TOC" role="doc-toc" class="toc-active"> + <h2 id="toc-title">On this page</h2> + + <ul> + <li><a href="#installing-hierarchicalforecast" id="toc-installing-hierarchicalforecast" class="nav-link active" data-scroll-target="#installing-hierarchicalforecast">1. Installing HierarchicalForecast</a></li> + <li><a href="#preparing-tourisml-dataset" id="toc-preparing-tourisml-dataset" class="nav-link" data-scroll-target="#preparing-tourisml-dataset">2. Preparing TourismL Dataset</a> + <ul class="collapse"> + <li><a href="#read-hierarchical-dataset" id="toc-read-hierarchical-dataset" class="nav-link" data-scroll-target="#read-hierarchical-dataset">2.1 Read Hierarchical Dataset</a></li> + <li><a href="#statsforecasts-base-predictions" id="toc-statsforecasts-base-predictions" class="nav-link" data-scroll-target="#statsforecasts-base-predictions">2.2 StatsForecastās Base Predictions</a></li> + </ul></li> + <li><a href="#reconciliate-predictions" id="toc-reconciliate-predictions" class="nav-link" data-scroll-target="#reconciliate-predictions">3. Reconciliate Predictions</a></li> + <li><a href="#evaluation" id="toc-evaluation" class="nav-link" data-scroll-target="#evaluation">4. Evaluation</a></li> + <li><a href="#references" id="toc-references" class="nav-link" data-scroll-target="#references">References</a></li> + </ul> +<div class="toc-actions"><div><i class="bi bi-github"></i></div><div class="action-links"><p><a href="https://github.com/Nixtla/hierarchicalforecast/issues/new" class="toc-action">Report an issue</a></p></div></div></nav> + </div> +<!-- main --> +<main class="content" id="quarto-document-content"> + +<header id="title-block-header" class="quarto-title-block default"> +<div class="quarto-title"> +<h1 class="title">Probabilistic Forecast Evaluation</h1> +</div> + +<div> + <div class="description"> + Hierarchical Forecastās reconciliation and evaluation. + </div> +</div> + + +<div class="quarto-title-meta"> + + + + + </div> + + +</header> + +<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! --> +<p>This notebook offers a step to step guide to create a hierarchical forecasting pipeline.</p> +<p>In the pipeline we will use <code>HierarchicalForecast</code> and <code>StatsForecast</code> core class, to create base predictions, reconcile and evaluate them.</p> +<p>We will use the TourismL dataset that summarizes large Australian national visitor survey.</p> +<p>Outline 1. Installing Packages 2. Prepare TourismL dataset - Read and aggregate - StatsForecastās Base Predictions 3. Reconciliar 4. Evaluar</p> +<p><a href="https://colab.research.google.com/github/Nixtla/hierarchicalforecast/blob/main/nbs/examples/TourismLarge-Evaluation.ipynb" target="_parent"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"></a></p> +<section id="installing-hierarchicalforecast" class="level2"> +<h2 class="anchored" data-anchor-id="installing-hierarchicalforecast">1. Installing HierarchicalForecast</h2> +<p>We assume you have StatsForecast and HierarchicalForecast already installed, if not check this guide for instructions on how to install HierarchicalForecast.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb1"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="co"># %%capture</span></span> +<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="co"># !pip install hierarchicalforecast</span></span> +<span id="cb1-3"><a href="#cb1-3" aria-hidden="true" tabindex="-1"></a><span class="co"># !pip install -U numba statsforecast datasetsforecast</span></span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb2"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> os</span> +<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> numpy <span class="im">as</span> np</span> +<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> pandas <span class="im">as</span> pd</span> +<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> matplotlib.pyplot <span class="im">as</span> plt</span> +<span id="cb2-5"><a href="#cb2-5" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb2-6"><a href="#cb2-6" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> statsforecast.core <span class="im">import</span> StatsForecast</span> +<span id="cb2-7"><a href="#cb2-7" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> statsforecast.models <span class="im">import</span> AutoARIMA, Naive</span> +<span id="cb2-8"><a href="#cb2-8" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb2-9"><a href="#cb2-9" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> hierarchicalforecast.core <span class="im">import</span> HierarchicalReconciliation</span> +<span id="cb2-10"><a href="#cb2-10" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> hierarchicalforecast.evaluation <span class="im">import</span> HierarchicalEvaluation</span> +<span id="cb2-11"><a href="#cb2-11" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> hierarchicalforecast.methods <span class="im">import</span> BottomUp, TopDown, MinTrace, ERM</span> +<span id="cb2-12"><a href="#cb2-12" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb2-13"><a href="#cb2-13" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> hierarchicalforecast.utils <span class="im">import</span> is_strictly_hierarchical</span> +<span id="cb2-14"><a href="#cb2-14" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> hierarchicalforecast.utils <span class="im">import</span> HierarchicalPlot, CodeTimer</span> +<span id="cb2-15"><a href="#cb2-15" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> hierarchicalforecast.evaluation <span class="im">import</span> scaled_crps, msse, energy_score</span> +<span id="cb2-16"><a href="#cb2-16" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb2-17"><a href="#cb2-17" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> datasetsforecast.hierarchical <span class="im">import</span> HierarchicalData, HierarchicalInfo</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-stderr"> +<pre><code>/Users/cchallu/opt/anaconda3/envs/hierarchicalforecast/lib/python3.10/site-packages/statsforecast/core.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html + from tqdm.autonotebook import tqdm</code></pre> +</div> +</div> +</section> +<section id="preparing-tourisml-dataset" class="level2"> +<h2 class="anchored" data-anchor-id="preparing-tourisml-dataset">2. Preparing TourismL Dataset</h2> +<section id="read-hierarchical-dataset" class="level3"> +<h3 class="anchored" data-anchor-id="read-hierarchical-dataset">2.1 Read Hierarchical Dataset</h3> +<div class="cell"> +<div class="sourceCode cell-code" id="cb4"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="co"># ['Labour', 'Traffic', 'TourismSmall', 'TourismLarge', 'Wiki2']</span></span> +<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a>dataset <span class="op">=</span> <span class="st">'TourismSmall'</span> <span class="co"># 'TourismLarge'</span></span> +<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a>verbose <span class="op">=</span> <span class="va">True</span></span> +<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a>intervals_method <span class="op">=</span> <span class="st">'bootstrap'</span></span> +<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a>LEVEL <span class="op">=</span> np.arange(<span class="dv">0</span>, <span class="dv">100</span>, <span class="dv">2</span>)</span> +<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a>qs <span class="op">=</span> [[<span class="dv">50</span><span class="op">-</span>lv<span class="op">/</span><span class="dv">2</span>, <span class="dv">50</span><span class="op">+</span>lv<span class="op">/</span><span class="dv">2</span>] <span class="cf">for</span> lv <span class="kw">in</span> LEVEL]</span> +<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a>QUANTILES <span class="op">=</span> np.sort(np.concatenate(qs)<span class="op">/</span><span class="dv">100</span>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb5"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="cf">with</span> CodeTimer(<span class="st">'Read and Parse data '</span>, verbose):</span> +<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a> <span class="bu">print</span>(<span class="ss">f'</span><span class="sc">{</span>dataset<span class="sc">}</span><span class="ss">'</span>)</span> +<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> <span class="kw">not</span> os.path.exists(<span class="st">'./data'</span>):</span> +<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a> os.makedirs(<span class="st">'./data'</span>)</span> +<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a> </span> +<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a> dataset_info <span class="op">=</span> HierarchicalInfo[dataset]</span> +<span id="cb5-7"><a href="#cb5-7" aria-hidden="true" tabindex="-1"></a> Y_df, S_df, tags <span class="op">=</span> HierarchicalData.load(directory<span class="op">=</span><span class="ss">f'./data/</span><span class="sc">{</span>dataset<span class="sc">}</span><span class="ss">'</span>, group<span class="op">=</span>dataset)</span> +<span id="cb5-8"><a href="#cb5-8" aria-hidden="true" tabindex="-1"></a> Y_df[<span class="st">'ds'</span>] <span class="op">=</span> pd.to_datetime(Y_df[<span class="st">'ds'</span>])</span> +<span id="cb5-9"><a href="#cb5-9" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb5-10"><a href="#cb5-10" aria-hidden="true" tabindex="-1"></a> <span class="co"># Train/Test Splits</span></span> +<span id="cb5-11"><a href="#cb5-11" aria-hidden="true" tabindex="-1"></a> horizon <span class="op">=</span> dataset_info.horizon</span> +<span id="cb5-12"><a href="#cb5-12" aria-hidden="true" tabindex="-1"></a> seasonality <span class="op">=</span> dataset_info.seasonality</span> +<span id="cb5-13"><a href="#cb5-13" aria-hidden="true" tabindex="-1"></a> Y_test_df <span class="op">=</span> Y_df.groupby(<span class="st">'unique_id'</span>).tail(horizon)</span> +<span id="cb5-14"><a href="#cb5-14" aria-hidden="true" tabindex="-1"></a> Y_train_df <span class="op">=</span> Y_df.drop(Y_test_df.index)</span> +<span id="cb5-15"><a href="#cb5-15" aria-hidden="true" tabindex="-1"></a> Y_test_df <span class="op">=</span> Y_test_df.set_index(<span class="st">'unique_id'</span>)</span> +<span id="cb5-16"><a href="#cb5-16" aria-hidden="true" tabindex="-1"></a> Y_train_df <span class="op">=</span> Y_train_df.set_index(<span class="st">'unique_id'</span>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-stdout"> +<pre><code>TourismSmall +Code block 'Read and Parse data ' took: 0.99873 seconds</code></pre> +</div> +<div class="cell-output cell-output-stderr"> +<pre><code>100%|āāāāāāāāāā| 1.30M/1.30M [00:00<00:00, 2.74MiB/s] +INFO:datasetsforecast.utils:Successfully downloaded datasets.zip, 1297279, bytes. +INFO:datasetsforecast.utils:Decompressing zip file... +INFO:datasetsforecast.utils:Successfully decompressed data/TourismSmall/hierarchical/datasets.zip</code></pre> +</div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb8"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a>dataset_info.seasonality</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<pre><code>4</code></pre> +</div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb10"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a>hplot <span class="op">=</span> HierarchicalPlot(S<span class="op">=</span>S_df, tags<span class="op">=</span>tags)</span> +<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a>hplot.plot_summing_matrix()</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<p><img src="TourismLarge-Evaluation_files/figure-html/cell-7-output-1.png" class="img-fluid"></p> +</div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb11"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a>Y_train_df</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<div> + + +<table class="dataframe table table-sm table-striped small" data-quarto-postprocess="true" data-border="1"> +<thead> +<tr class="header"> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th">ds</th> +<th data-quarto-table-cell-role="th">y</th> +</tr> +<tr class="odd"> +<th data-quarto-table-cell-role="th">unique_id</th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td data-quarto-table-cell-role="th">total</td> +<td>1998-03-31</td> +<td>84503</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">total</td> +<td>1998-06-30</td> +<td>65312</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">total</td> +<td>1998-09-30</td> +<td>72753</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">total</td> +<td>1998-12-31</td> +<td>70880</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">total</td> +<td>1999-03-31</td> +<td>86893</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">...</td> +<td>...</td> +<td>...</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">nt-oth-noncity</td> +<td>2003-12-31</td> +<td>132</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">nt-oth-noncity</td> +<td>2004-03-31</td> +<td>12</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">nt-oth-noncity</td> +<td>2004-06-30</td> +<td>40</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">nt-oth-noncity</td> +<td>2004-09-30</td> +<td>186</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">nt-oth-noncity</td> +<td>2004-12-31</td> +<td>144</td> +</tr> +</tbody> +</table> + +<p>2492 rows Ć 2 columns</p> +</div> +</div> +</div> +</section> +<section id="statsforecasts-base-predictions" class="level3"> +<h3 class="anchored" data-anchor-id="statsforecasts-base-predictions">2.2 StatsForecastās Base Predictions</h3> +<p>This cell computes the base predictions <code>Y_hat_df</code> for all the series in <code>Y_df</code> using StatsForecastās <code>AutoARIMA</code>. Additionally we obtain insample predictions <code>Y_fitted_df</code> for the methods that require them.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb12"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="cf">with</span> CodeTimer(<span class="st">'Fit/Predict Model '</span>, verbose):</span> +<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a> <span class="co"># Read to avoid unnecesary AutoARIMA computation</span></span> +<span id="cb12-3"><a href="#cb12-3" aria-hidden="true" tabindex="-1"></a> yhat_file <span class="op">=</span> <span class="ss">f'./data/</span><span class="sc">{</span>dataset<span class="sc">}</span><span class="ss">/Y_hat.csv'</span></span> +<span id="cb12-4"><a href="#cb12-4" aria-hidden="true" tabindex="-1"></a> yfitted_file <span class="op">=</span> <span class="ss">f'./data/</span><span class="sc">{</span>dataset<span class="sc">}</span><span class="ss">/Y_fitted.csv'</span></span> +<span id="cb12-5"><a href="#cb12-5" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb12-6"><a href="#cb12-6" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> os.path.exists(yhat_file):</span> +<span id="cb12-7"><a href="#cb12-7" aria-hidden="true" tabindex="-1"></a> Y_hat_df <span class="op">=</span> pd.read_csv(yhat_file)</span> +<span id="cb12-8"><a href="#cb12-8" aria-hidden="true" tabindex="-1"></a> Y_fitted_df <span class="op">=</span> pd.read_csv(yfitted_file)</span> +<span id="cb12-9"><a href="#cb12-9" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb12-10"><a href="#cb12-10" aria-hidden="true" tabindex="-1"></a> Y_hat_df <span class="op">=</span> Y_hat_df.set_index(<span class="st">'unique_id'</span>)</span> +<span id="cb12-11"><a href="#cb12-11" aria-hidden="true" tabindex="-1"></a> Y_fitted_df <span class="op">=</span> Y_fitted_df.set_index(<span class="st">'unique_id'</span>)</span> +<span id="cb12-12"><a href="#cb12-12" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb12-13"><a href="#cb12-13" aria-hidden="true" tabindex="-1"></a> <span class="cf">else</span>:</span> +<span id="cb12-14"><a href="#cb12-14" aria-hidden="true" tabindex="-1"></a> fcst <span class="op">=</span> StatsForecast(</span> +<span id="cb12-15"><a href="#cb12-15" aria-hidden="true" tabindex="-1"></a> df<span class="op">=</span>Y_train_df, </span> +<span id="cb12-16"><a href="#cb12-16" aria-hidden="true" tabindex="-1"></a> models<span class="op">=</span>[AutoARIMA(season_length<span class="op">=</span>seasonality)],</span> +<span id="cb12-17"><a href="#cb12-17" aria-hidden="true" tabindex="-1"></a> fallback_model<span class="op">=</span>[Naive()],</span> +<span id="cb12-18"><a href="#cb12-18" aria-hidden="true" tabindex="-1"></a> freq<span class="op">=</span><span class="st">'M'</span>, </span> +<span id="cb12-19"><a href="#cb12-19" aria-hidden="true" tabindex="-1"></a> n_jobs<span class="op">=-</span><span class="dv">1</span></span> +<span id="cb12-20"><a href="#cb12-20" aria-hidden="true" tabindex="-1"></a> )</span> +<span id="cb12-21"><a href="#cb12-21" aria-hidden="true" tabindex="-1"></a> Y_hat_df <span class="op">=</span> fcst.forecast(h<span class="op">=</span>horizon, fitted<span class="op">=</span><span class="va">True</span>, level<span class="op">=</span>LEVEL)</span> +<span id="cb12-22"><a href="#cb12-22" aria-hidden="true" tabindex="-1"></a> Y_fitted_df <span class="op">=</span> fcst.forecast_fitted_values()</span> +<span id="cb12-23"><a href="#cb12-23" aria-hidden="true" tabindex="-1"></a> Y_hat_df.to_csv(yhat_file)</span> +<span id="cb12-24"><a href="#cb12-24" aria-hidden="true" tabindex="-1"></a> Y_fitted_df.to_csv(yfitted_file)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb13"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a>Y_hat_df</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<div> + + +<table class="dataframe table table-sm table-striped small" data-quarto-postprocess="true" data-border="1"> +<thead> +<tr class="header"> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th">ds</th> +<th data-quarto-table-cell-role="th">AutoARIMA</th> +<th data-quarto-table-cell-role="th">AutoARIMA-lo-98</th> +<th data-quarto-table-cell-role="th">AutoARIMA-lo-96</th> +<th data-quarto-table-cell-role="th">AutoARIMA-lo-94</th> +<th data-quarto-table-cell-role="th">AutoARIMA-lo-92</th> +<th data-quarto-table-cell-role="th">AutoARIMA-lo-90</th> +<th data-quarto-table-cell-role="th">AutoARIMA-lo-88</th> +<th data-quarto-table-cell-role="th">AutoARIMA-lo-86</th> +<th data-quarto-table-cell-role="th">AutoARIMA-lo-84</th> +<th data-quarto-table-cell-role="th">...</th> +<th data-quarto-table-cell-role="th">AutoARIMA-hi-80</th> +<th data-quarto-table-cell-role="th">AutoARIMA-hi-82</th> +<th data-quarto-table-cell-role="th">AutoARIMA-hi-84</th> +<th data-quarto-table-cell-role="th">AutoARIMA-hi-86</th> +<th data-quarto-table-cell-role="th">AutoARIMA-hi-88</th> +<th data-quarto-table-cell-role="th">AutoARIMA-hi-90</th> +<th data-quarto-table-cell-role="th">AutoARIMA-hi-92</th> +<th data-quarto-table-cell-role="th">AutoARIMA-hi-94</th> +<th data-quarto-table-cell-role="th">AutoARIMA-hi-96</th> +<th data-quarto-table-cell-role="th">AutoARIMA-hi-98</th> +</tr> +<tr class="odd"> +<th data-quarto-table-cell-role="th">unique_id</th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td data-quarto-table-cell-role="th">bus</td> +<td>2005-01-31</td> +<td>9673.424805</td> +<td>7436.356445</td> +<td>7698.493652</td> +<td>7864.811523</td> +<td>7989.925781</td> +<td>8091.696289</td> +<td>8178.319336</td> +<td>8254.270508</td> +<td>8322.276367</td> +<td>...</td> +<td>10905.793945</td> +<td>10962.725586</td> +<td>11024.573242</td> +<td>11092.579102</td> +<td>11168.530273</td> +<td>11255.153320</td> +<td>11356.923828</td> +<td>11482.038086</td> +<td>11648.356445</td> +<td>11910.493164</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">bus</td> +<td>2005-02-28</td> +<td>10393.900391</td> +<td>8156.831543</td> +<td>8418.968750</td> +<td>8585.287109</td> +<td>8710.401367</td> +<td>8812.171875</td> +<td>8898.794922</td> +<td>8974.746094</td> +<td>9042.751953</td> +<td>...</td> +<td>11626.269531</td> +<td>11683.200195</td> +<td>11745.048828</td> +<td>11813.054688</td> +<td>11889.005859</td> +<td>11975.628906</td> +<td>12077.399414</td> +<td>12202.513672</td> +<td>12368.832031</td> +<td>12630.968750</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">bus</td> +<td>2005-03-31</td> +<td>12028.134766</td> +<td>9791.066406</td> +<td>10053.204102</td> +<td>10219.521484</td> +<td>10344.635742</td> +<td>10446.406250</td> +<td>10533.029297</td> +<td>10608.981445</td> +<td>10676.986328</td> +<td>...</td> +<td>13260.503906</td> +<td>13317.435547</td> +<td>13379.283203</td> +<td>13447.289062</td> +<td>13523.240234</td> +<td>13609.863281</td> +<td>13711.633789</td> +<td>13836.748047</td> +<td>14003.066406</td> +<td>14265.203125</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">bus</td> +<td>2005-04-30</td> +<td>10995.679688</td> +<td>8758.610352</td> +<td>9020.748047</td> +<td>9187.065430</td> +<td>9312.179688</td> +<td>9413.951172</td> +<td>9500.574219</td> +<td>9576.525391</td> +<td>9644.531250</td> +<td>...</td> +<td>12228.047852</td> +<td>12284.979492</td> +<td>12346.828125</td> +<td>12414.833008</td> +<td>12490.785156</td> +<td>12577.407227</td> +<td>12679.178711</td> +<td>12804.292969</td> +<td>12970.610352</td> +<td>13232.748047</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">bus</td> +<td>2005-05-31</td> +<td>9673.424805</td> +<td>7262.085449</td> +<td>7544.643555</td> +<td>7723.917480</td> +<td>7858.778320</td> +<td>7968.477539</td> +<td>8061.848633</td> +<td>8143.716797</td> +<td>8217.019531</td> +<td>...</td> +<td>11001.796875</td> +<td>11063.164062</td> +<td>11129.830078</td> +<td>11203.132812</td> +<td>11285.000977</td> +<td>11378.372070</td> +<td>11488.071289</td> +<td>11622.932617</td> +<td>11802.206055</td> +<td>12084.764648</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">wa-vfr-noncity</td> +<td>2005-04-30</td> +<td>904.125549</td> +<td>463.371521</td> +<td>515.018616</td> +<td>547.787048</td> +<td>572.437439</td> +<td>592.488647</td> +<td>609.555359</td> +<td>624.519531</td> +<td>637.918213</td> +<td>...</td> +<td>1146.930542</td> +<td>1158.147339</td> +<td>1170.332886</td> +<td>1183.731567</td> +<td>1198.695679</td> +<td>1215.762451</td> +<td>1235.813721</td> +<td>1260.464111</td> +<td>1293.232544</td> +<td>1344.879517</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">wa-vfr-noncity</td> +<td>2005-05-31</td> +<td>904.125549</td> +<td>457.607361</td> +<td>509.929901</td> +<td>543.126831</td> +<td>568.099670</td> +<td>588.413086</td> +<td>605.703003</td> +<td>620.862854</td> +<td>634.436707</td> +<td>...</td> +<td>1150.105957</td> +<td>1161.469482</td> +<td>1173.814331</td> +<td>1187.388184</td> +<td>1202.548096</td> +<td>1219.838013</td> +<td>1240.151489</td> +<td>1265.124268</td> +<td>1298.321167</td> +<td>1350.643677</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">wa-vfr-noncity</td> +<td>2005-06-30</td> +<td>904.125549</td> +<td>451.916687</td> +<td>504.906036</td> +<td>538.526062</td> +<td>563.817139</td> +<td>584.389465</td> +<td>601.899719</td> +<td>617.252808</td> +<td>630.999634</td> +<td>...</td> +<td>1153.240967</td> +<td>1164.749268</td> +<td>1177.251465</td> +<td>1190.998291</td> +<td>1206.351440</td> +<td>1223.861694</td> +<td>1244.433960</td> +<td>1269.724976</td> +<td>1303.345093</td> +<td>1356.334473</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">wa-vfr-noncity</td> +<td>2005-07-31</td> +<td>904.125549</td> +<td>446.296722</td> +<td>499.944611</td> +<td>533.982483</td> +<td>559.587830</td> +<td>580.415833</td> +<td>598.143738</td> +<td>613.687622</td> +<td>627.605286</td> +<td>...</td> +<td>1156.336914</td> +<td>1167.988159</td> +<td>1180.645752</td> +<td>1194.563477</td> +<td>1210.107422</td> +<td>1227.835327</td> +<td>1248.663208</td> +<td>1274.268677</td> +<td>1308.306519</td> +<td>1361.954346</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">wa-vfr-noncity</td> +<td>2005-08-31</td> +<td>904.125549</td> +<td>440.744904</td> +<td>495.043365</td> +<td>529.493958</td> +<td>555.409851</td> +<td>576.490417</td> +<td>594.433289</td> +<td>610.165649</td> +<td>624.252136</td> +<td>...</td> +<td>1159.395264</td> +<td>1171.187866</td> +<td>1183.999023</td> +<td>1198.085449</td> +<td>1213.817871</td> +<td>1231.760742</td> +<td>1252.841309</td> +<td>1278.757080</td> +<td>1313.207764</td> +<td>1367.506226</td> +</tr> +</tbody> +</table> + +<p>712 rows Ć 102 columns</p> +</div> +</div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb14"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a>Y_fitted_df</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<div> + + +<table class="dataframe table table-sm table-striped small" data-quarto-postprocess="true" data-border="1"> +<thead> +<tr class="header"> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th">ds</th> +<th data-quarto-table-cell-role="th">y</th> +<th data-quarto-table-cell-role="th">AutoARIMA</th> +<th data-quarto-table-cell-role="th">AutoARIMA-lo-98</th> +<th data-quarto-table-cell-role="th">AutoARIMA-lo-96</th> +<th data-quarto-table-cell-role="th">AutoARIMA-lo-94</th> +<th data-quarto-table-cell-role="th">AutoARIMA-lo-92</th> +<th data-quarto-table-cell-role="th">AutoARIMA-lo-90</th> +<th data-quarto-table-cell-role="th">AutoARIMA-lo-88</th> +<th data-quarto-table-cell-role="th">AutoARIMA-lo-86</th> +<th data-quarto-table-cell-role="th">...</th> +<th data-quarto-table-cell-role="th">AutoARIMA-hi-80</th> +<th data-quarto-table-cell-role="th">AutoARIMA-hi-82</th> +<th data-quarto-table-cell-role="th">AutoARIMA-hi-84</th> +<th data-quarto-table-cell-role="th">AutoARIMA-hi-86</th> +<th data-quarto-table-cell-role="th">AutoARIMA-hi-88</th> +<th data-quarto-table-cell-role="th">AutoARIMA-hi-90</th> +<th data-quarto-table-cell-role="th">AutoARIMA-hi-92</th> +<th data-quarto-table-cell-role="th">AutoARIMA-hi-94</th> +<th data-quarto-table-cell-role="th">AutoARIMA-hi-96</th> +<th data-quarto-table-cell-role="th">AutoARIMA-hi-98</th> +</tr> +<tr class="odd"> +<th data-quarto-table-cell-role="th">unique_id</th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th"></th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td data-quarto-table-cell-role="th">bus</td> +<td>1998-03-31</td> +<td>9815.0</td> +<td>9805.184570</td> +<td>7568.648926</td> +<td>7830.724121</td> +<td>7997.001953</td> +<td>8122.086426</td> +<td>8223.833008</td> +<td>8310.435547</td> +<td>8386.369141</td> +<td>...</td> +<td>11037.260742</td> +<td>11094.178711</td> +<td>11156.011719</td> +<td>11224.000977</td> +<td>11299.934570</td> +<td>11386.537109</td> +<td>11488.283203</td> +<td>11613.368164</td> +<td>11779.646484</td> +<td>12041.720703</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">bus</td> +<td>1998-06-30</td> +<td>11823.0</td> +<td>11811.176758</td> +<td>9574.640625</td> +<td>9836.715820</td> +<td>10002.994141</td> +<td>10128.078125</td> +<td>10229.825195</td> +<td>10316.427734</td> +<td>10392.361328</td> +<td>...</td> +<td>13043.252930</td> +<td>13100.169922</td> +<td>13162.003906</td> +<td>13229.993164</td> +<td>13305.926758</td> +<td>13392.528320</td> +<td>13494.275391</td> +<td>13619.360352</td> +<td>13785.637695</td> +<td>14047.712891</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">bus</td> +<td>1998-09-30</td> +<td>13565.0</td> +<td>13551.434570</td> +<td>11314.899414</td> +<td>11576.973633</td> +<td>11743.251953</td> +<td>11868.336914</td> +<td>11970.083008</td> +<td>12056.685547</td> +<td>12132.619141</td> +<td>...</td> +<td>14783.510742</td> +<td>14840.428711</td> +<td>14902.261719</td> +<td>14970.250977</td> +<td>15046.184570</td> +<td>15132.787109</td> +<td>15234.533203</td> +<td>15359.618164</td> +<td>15525.896484</td> +<td>15787.970703</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">bus</td> +<td>1998-12-31</td> +<td>11478.0</td> +<td>11466.522461</td> +<td>9229.986328</td> +<td>9492.060547</td> +<td>9658.338867</td> +<td>9783.423828</td> +<td>9885.169922</td> +<td>9971.772461</td> +<td>10047.706055</td> +<td>...</td> +<td>12698.597656</td> +<td>12755.515625</td> +<td>12817.348633</td> +<td>12885.337891</td> +<td>12961.271484</td> +<td>13047.874023</td> +<td>13149.620117</td> +<td>13274.705078</td> +<td>13440.983398</td> +<td>13703.057617</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">bus</td> +<td>1999-03-31</td> +<td>10027.0</td> +<td>9845.011719</td> +<td>7608.475586</td> +<td>7870.550781</td> +<td>8036.828613</td> +<td>8161.913086</td> +<td>8263.660156</td> +<td>8350.262695</td> +<td>8426.195312</td> +<td>...</td> +<td>11077.086914</td> +<td>11134.004883</td> +<td>11195.838867</td> +<td>11263.828125</td> +<td>11339.760742</td> +<td>11426.363281</td> +<td>11528.110352</td> +<td>11653.194336</td> +<td>11819.472656</td> +<td>12081.547852</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">wa-vfr-noncity</td> +<td>2003-12-31</td> +<td>1177.0</td> +<td>927.351196</td> +<td>504.362732</td> +<td>553.928040</td> +<td>585.375671</td> +<td>609.032471</td> +<td>628.275513</td> +<td>644.654297</td> +<td>659.015320</td> +<td>...</td> +<td>1160.369507</td> +<td>1171.134155</td> +<td>1182.828491</td> +<td>1195.687012</td> +<td>1210.048096</td> +<td>1226.426880</td> +<td>1245.669922</td> +<td>1269.326660</td> +<td>1300.774292</td> +<td>1350.339600</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">wa-vfr-noncity</td> +<td>2004-03-31</td> +<td>956.0</td> +<td>969.565552</td> +<td>546.577087</td> +<td>596.142456</td> +<td>627.590027</td> +<td>651.246887</td> +<td>670.489868</td> +<td>686.868652</td> +<td>701.229675</td> +<td>...</td> +<td>1202.583862</td> +<td>1213.348511</td> +<td>1225.042847</td> +<td>1237.901489</td> +<td>1252.262451</td> +<td>1268.641235</td> +<td>1287.884277</td> +<td>1311.541016</td> +<td>1342.988647</td> +<td>1392.554077</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">wa-vfr-noncity</td> +<td>2004-06-30</td> +<td>772.0</td> +<td>967.268921</td> +<td>544.280457</td> +<td>593.845764</td> +<td>625.293396</td> +<td>648.950195</td> +<td>668.193237</td> +<td>684.572021</td> +<td>698.933044</td> +<td>...</td> +<td>1200.287109</td> +<td>1211.051880</td> +<td>1222.746216</td> +<td>1235.604736</td> +<td>1249.965820</td> +<td>1266.344604</td> +<td>1285.587646</td> +<td>1309.244385</td> +<td>1340.692017</td> +<td>1390.257324</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">wa-vfr-noncity</td> +<td>2004-09-30</td> +<td>885.0</td> +<td>934.251831</td> +<td>511.263336</td> +<td>560.828674</td> +<td>592.276306</td> +<td>615.933105</td> +<td>635.176086</td> +<td>651.554932</td> +<td>665.915955</td> +<td>...</td> +<td>1167.270020</td> +<td>1178.034790</td> +<td>1189.729126</td> +<td>1202.587646</td> +<td>1216.948730</td> +<td>1233.327515</td> +<td>1252.570557</td> +<td>1276.227295</td> +<td>1307.674927</td> +<td>1357.240234</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">wa-vfr-noncity</td> +<td>2004-12-31</td> +<td>797.0</td> +<td>925.923462</td> +<td>502.934998</td> +<td>552.500305</td> +<td>583.947937</td> +<td>607.604736</td> +<td>626.847778</td> +<td>643.226562</td> +<td>657.587585</td> +<td>...</td> +<td>1158.941772</td> +<td>1169.706421</td> +<td>1181.400757</td> +<td>1194.259277</td> +<td>1208.620361</td> +<td>1224.999146</td> +<td>1244.242188</td> +<td>1267.898926</td> +<td>1299.346558</td> +<td>1348.911865</td> +</tr> +</tbody> +</table> + +<p>2492 rows Ć 103 columns</p> +</div> +</div> +</div> +</section> +</section> +<section id="reconciliate-predictions" class="level2"> +<h2 class="anchored" data-anchor-id="reconciliate-predictions">3. Reconciliate Predictions</h2> +<div class="cell"> +<div class="sourceCode cell-code" id="cb15"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="cf">with</span> CodeTimer(<span class="st">'Reconcile Predictions '</span>, verbose):</span> +<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> is_strictly_hierarchical(S<span class="op">=</span>S_df.values.astype(np.float32), </span> +<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a> tags<span class="op">=</span>{key: S_df.index.get_indexer(val) <span class="cf">for</span> key, val <span class="kw">in</span> tags.items()}):</span> +<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a> reconcilers <span class="op">=</span> [</span> +<span id="cb15-5"><a href="#cb15-5" aria-hidden="true" tabindex="-1"></a> BottomUp(),</span> +<span id="cb15-6"><a href="#cb15-6" aria-hidden="true" tabindex="-1"></a> TopDown(method<span class="op">=</span><span class="st">'average_proportions'</span>),</span> +<span id="cb15-7"><a href="#cb15-7" aria-hidden="true" tabindex="-1"></a> TopDown(method<span class="op">=</span><span class="st">'proportion_averages'</span>),</span> +<span id="cb15-8"><a href="#cb15-8" aria-hidden="true" tabindex="-1"></a> MinTrace(method<span class="op">=</span><span class="st">'ols'</span>),</span> +<span id="cb15-9"><a href="#cb15-9" aria-hidden="true" tabindex="-1"></a> MinTrace(method<span class="op">=</span><span class="st">'wls_var'</span>),</span> +<span id="cb15-10"><a href="#cb15-10" aria-hidden="true" tabindex="-1"></a> MinTrace(method<span class="op">=</span><span class="st">'mint_shrink'</span>),</span> +<span id="cb15-11"><a href="#cb15-11" aria-hidden="true" tabindex="-1"></a> <span class="co">#ERM(method='reg_bu', lambda_reg=100) # Extremely inneficient</span></span> +<span id="cb15-12"><a href="#cb15-12" aria-hidden="true" tabindex="-1"></a> ERM(method<span class="op">=</span><span class="st">'closed'</span>)</span> +<span id="cb15-13"><a href="#cb15-13" aria-hidden="true" tabindex="-1"></a> ]</span> +<span id="cb15-14"><a href="#cb15-14" aria-hidden="true" tabindex="-1"></a> <span class="cf">else</span>:</span> +<span id="cb15-15"><a href="#cb15-15" aria-hidden="true" tabindex="-1"></a> reconcilers <span class="op">=</span> [</span> +<span id="cb15-16"><a href="#cb15-16" aria-hidden="true" tabindex="-1"></a> BottomUp(),</span> +<span id="cb15-17"><a href="#cb15-17" aria-hidden="true" tabindex="-1"></a> MinTrace(method<span class="op">=</span><span class="st">'ols'</span>),</span> +<span id="cb15-18"><a href="#cb15-18" aria-hidden="true" tabindex="-1"></a> MinTrace(method<span class="op">=</span><span class="st">'wls_var'</span>),</span> +<span id="cb15-19"><a href="#cb15-19" aria-hidden="true" tabindex="-1"></a> MinTrace(method<span class="op">=</span><span class="st">'mint_shrink'</span>),</span> +<span id="cb15-20"><a href="#cb15-20" aria-hidden="true" tabindex="-1"></a> <span class="co">#ERM(method='reg_bu', lambda_reg=100) # Extremely inneficient</span></span> +<span id="cb15-21"><a href="#cb15-21" aria-hidden="true" tabindex="-1"></a> ERM(method<span class="op">=</span><span class="st">'closed'</span>)</span> +<span id="cb15-22"><a href="#cb15-22" aria-hidden="true" tabindex="-1"></a> ]</span> +<span id="cb15-23"><a href="#cb15-23" aria-hidden="true" tabindex="-1"></a> </span> +<span id="cb15-24"><a href="#cb15-24" aria-hidden="true" tabindex="-1"></a> hrec <span class="op">=</span> HierarchicalReconciliation(reconcilers<span class="op">=</span>reconcilers)</span> +<span id="cb15-25"><a href="#cb15-25" aria-hidden="true" tabindex="-1"></a> Y_rec_df <span class="op">=</span> hrec.bootstrap_reconcile(Y_hat_df<span class="op">=</span>Y_hat_df,</span> +<span id="cb15-26"><a href="#cb15-26" aria-hidden="true" tabindex="-1"></a> Y_df<span class="op">=</span>Y_fitted_df,</span> +<span id="cb15-27"><a href="#cb15-27" aria-hidden="true" tabindex="-1"></a> S_df<span class="op">=</span>S_df, tags<span class="op">=</span>tags,</span> +<span id="cb15-28"><a href="#cb15-28" aria-hidden="true" tabindex="-1"></a> level<span class="op">=</span>LEVEL,</span> +<span id="cb15-29"><a href="#cb15-29" aria-hidden="true" tabindex="-1"></a> intervals_method<span class="op">=</span>intervals_method,</span> +<span id="cb15-30"><a href="#cb15-30" aria-hidden="true" tabindex="-1"></a> num_samples<span class="op">=</span><span class="dv">10</span>, num_seeds<span class="op">=</span><span class="dv">10</span>)</span> +<span id="cb15-31"><a href="#cb15-31" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb15-32"><a href="#cb15-32" aria-hidden="true" tabindex="-1"></a> <span class="co"># Matching Y_test/Y_rec/S index ordering</span></span> +<span id="cb15-33"><a href="#cb15-33" aria-hidden="true" tabindex="-1"></a> Y_test_df <span class="op">=</span> Y_test_df.reset_index()</span> +<span id="cb15-34"><a href="#cb15-34" aria-hidden="true" tabindex="-1"></a> Y_test_df.unique_id <span class="op">=</span> Y_test_df.unique_id.astype(<span class="st">'category'</span>)</span> +<span id="cb15-35"><a href="#cb15-35" aria-hidden="true" tabindex="-1"></a> Y_test_df.unique_id <span class="op">=</span> Y_test_df.unique_id.cat.set_categories(S_df.index)</span> +<span id="cb15-36"><a href="#cb15-36" aria-hidden="true" tabindex="-1"></a> Y_test_df <span class="op">=</span> Y_test_df.sort_values(by<span class="op">=</span>[<span class="st">'unique_id'</span>, <span class="st">'ds'</span>])</span> +<span id="cb15-37"><a href="#cb15-37" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb15-38"><a href="#cb15-38" aria-hidden="true" tabindex="-1"></a> Y_rec_df <span class="op">=</span> Y_rec_df.reset_index()</span> +<span id="cb15-39"><a href="#cb15-39" aria-hidden="true" tabindex="-1"></a> Y_rec_df.unique_id <span class="op">=</span> Y_rec_df.unique_id.astype(<span class="st">'category'</span>)</span> +<span id="cb15-40"><a href="#cb15-40" aria-hidden="true" tabindex="-1"></a> Y_rec_df.unique_id <span class="op">=</span> Y_rec_df.unique_id.cat.set_categories(S_df.index)</span> +<span id="cb15-41"><a href="#cb15-41" aria-hidden="true" tabindex="-1"></a> Y_rec_df <span class="op">=</span> Y_rec_df.sort_values(by<span class="op">=</span>[<span class="st">'seed'</span>, <span class="st">'unique_id'</span>, <span class="st">'ds'</span>])</span> +<span id="cb15-42"><a href="#cb15-42" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb15-43"><a href="#cb15-43" aria-hidden="true" tabindex="-1"></a> <span class="co"># Parsing model level columns</span></span> +<span id="cb15-44"><a href="#cb15-44" aria-hidden="true" tabindex="-1"></a> flat_cols <span class="op">=</span> <span class="bu">list</span>(hrec.level_names.keys())</span> +<span id="cb15-45"><a href="#cb15-45" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> model <span class="kw">in</span> hrec.level_names:</span> +<span id="cb15-46"><a href="#cb15-46" aria-hidden="true" tabindex="-1"></a> flat_cols <span class="op">+=</span> hrec.level_names[model]</span> +<span id="cb15-47"><a href="#cb15-47" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> model <span class="kw">in</span> hrec.sample_names:</span> +<span id="cb15-48"><a href="#cb15-48" aria-hidden="true" tabindex="-1"></a> flat_cols <span class="op">+=</span> hrec.sample_names[model]</span> +<span id="cb15-49"><a href="#cb15-49" aria-hidden="true" tabindex="-1"></a> y_rec <span class="op">=</span> Y_rec_df[flat_cols]</span> +<span id="cb15-50"><a href="#cb15-50" aria-hidden="true" tabindex="-1"></a> model_columns <span class="op">=</span> y_rec.columns</span> +<span id="cb15-51"><a href="#cb15-51" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb15-52"><a href="#cb15-52" aria-hidden="true" tabindex="-1"></a> n_series <span class="op">=</span> <span class="bu">len</span>(S_df)</span> +<span id="cb15-53"><a href="#cb15-53" aria-hidden="true" tabindex="-1"></a> n_seeds <span class="op">=</span> <span class="bu">len</span>(Y_rec_df.seed.unique())</span> +<span id="cb15-54"><a href="#cb15-54" aria-hidden="true" tabindex="-1"></a> y_rec <span class="op">=</span> y_rec.values.reshape(n_seeds, n_series, horizon, <span class="bu">len</span>(model_columns))</span> +<span id="cb15-55"><a href="#cb15-55" aria-hidden="true" tabindex="-1"></a> y_test <span class="op">=</span> Y_test_df[<span class="st">'y'</span>].values.reshape(n_series, horizon)</span> +<span id="cb15-56"><a href="#cb15-56" aria-hidden="true" tabindex="-1"></a> y_train <span class="op">=</span> Y_train_df[<span class="st">'y'</span>].values.reshape(n_series, <span class="op">-</span><span class="dv">1</span>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-stdout"> +<pre><code>Code block 'Reconcile Predictions ' took: 11.73492 seconds</code></pre> +</div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb17"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb17-1"><a href="#cb17-1" aria-hidden="true" tabindex="-1"></a><span class="co"># Qualitative evaluation, of parsed quantiles</span></span> +<span id="cb17-2"><a href="#cb17-2" aria-hidden="true" tabindex="-1"></a>row_idx <span class="op">=</span> <span class="dv">0</span></span> +<span id="cb17-3"><a href="#cb17-3" aria-hidden="true" tabindex="-1"></a>seed_idx <span class="op">=</span> <span class="dv">0</span></span> +<span id="cb17-4"><a href="#cb17-4" aria-hidden="true" tabindex="-1"></a>col_idxs <span class="op">=</span> model_columns.get_indexer(hrec.level_names[<span class="st">'AutoARIMA/BottomUp'</span>])</span> +<span id="cb17-5"><a href="#cb17-5" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> i, col <span class="kw">in</span> <span class="bu">enumerate</span>(col_idxs):</span> +<span id="cb17-6"><a href="#cb17-6" aria-hidden="true" tabindex="-1"></a> plt.plot(y_rec[seed_idx, row_idx,:,col], color<span class="op">=</span><span class="st">'orange'</span>, alpha<span class="op">=</span>i<span class="op">/</span><span class="dv">100</span>)</span> +<span id="cb17-7"><a href="#cb17-7" aria-hidden="true" tabindex="-1"></a><span class="cf">for</span> i, col <span class="kw">in</span> <span class="bu">enumerate</span>(col_idxs):</span> +<span id="cb17-8"><a href="#cb17-8" aria-hidden="true" tabindex="-1"></a> plt.plot(y_rec[seed_idx<span class="op">+</span><span class="dv">1</span>, row_idx,:,col], color<span class="op">=</span><span class="st">'green'</span>, alpha<span class="op">=</span>i<span class="op">/</span><span class="dv">100</span>)</span> +<span id="cb17-9"><a href="#cb17-9" aria-hidden="true" tabindex="-1"></a>plt.plot(y_test[row_idx,:], label<span class="op">=</span><span class="st">'True'</span>)</span> +<span id="cb17-10"><a href="#cb17-10" aria-hidden="true" tabindex="-1"></a>plt.title(<span class="ss">f'</span><span class="sc">{</span>S_df<span class="sc">.</span>index[row_idx]<span class="sc">}</span><span class="ss"> Visits </span><span class="ch">\n</span><span class="ss">'</span> <span class="op">+</span> <span class="op">\</span></span> +<span id="cb17-11"><a href="#cb17-11" aria-hidden="true" tabindex="-1"></a> <span class="ss">f'AutoARIMA/BottomUp-</span><span class="sc">{</span>intervals_method<span class="sc">}</span><span class="ss">'</span>)</span> +<span id="cb17-12"><a href="#cb17-12" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb17-13"><a href="#cb17-13" aria-hidden="true" tabindex="-1"></a>plt.legend()</span> +<span id="cb17-14"><a href="#cb17-14" aria-hidden="true" tabindex="-1"></a>plt.grid()</span> +<span id="cb17-15"><a href="#cb17-15" aria-hidden="true" tabindex="-1"></a>plt.show()</span> +<span id="cb17-16"><a href="#cb17-16" aria-hidden="true" tabindex="-1"></a>plt.close()</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<p><img src="TourismLarge-Evaluation_files/figure-html/cell-13-output-1.png" class="img-fluid"></p> +</div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb18"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb18-1"><a href="#cb18-1" aria-hidden="true" tabindex="-1"></a><span class="co">#Y_rec_df</span></span> +<span id="cb18-2"><a href="#cb18-2" aria-hidden="true" tabindex="-1"></a>td_levels <span class="op">=</span> hrec.level_names[<span class="st">'AutoARIMA/TopDown_method-average_proportions'</span>]</span> +<span id="cb18-3"><a href="#cb18-3" aria-hidden="true" tabindex="-1"></a>Y_rec_df[td_levels]</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<div> + + +<table class="dataframe table table-sm table-striped small" data-quarto-postprocess="true" data-border="1"> +<thead> +<tr class="header"> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th">AutoARIMA/TopDown_method-average_proportions-lo-98</th> +<th data-quarto-table-cell-role="th">AutoARIMA/TopDown_method-average_proportions-lo-96</th> +<th data-quarto-table-cell-role="th">AutoARIMA/TopDown_method-average_proportions-lo-94</th> +<th data-quarto-table-cell-role="th">AutoARIMA/TopDown_method-average_proportions-lo-92</th> +<th data-quarto-table-cell-role="th">AutoARIMA/TopDown_method-average_proportions-lo-90</th> +<th data-quarto-table-cell-role="th">AutoARIMA/TopDown_method-average_proportions-lo-88</th> +<th data-quarto-table-cell-role="th">AutoARIMA/TopDown_method-average_proportions-lo-86</th> +<th data-quarto-table-cell-role="th">AutoARIMA/TopDown_method-average_proportions-lo-84</th> +<th data-quarto-table-cell-role="th">AutoARIMA/TopDown_method-average_proportions-lo-82</th> +<th data-quarto-table-cell-role="th">AutoARIMA/TopDown_method-average_proportions-lo-80</th> +<th data-quarto-table-cell-role="th">...</th> +<th data-quarto-table-cell-role="th">AutoARIMA/TopDown_method-average_proportions-hi-80</th> +<th data-quarto-table-cell-role="th">AutoARIMA/TopDown_method-average_proportions-hi-82</th> +<th data-quarto-table-cell-role="th">AutoARIMA/TopDown_method-average_proportions-hi-84</th> +<th data-quarto-table-cell-role="th">AutoARIMA/TopDown_method-average_proportions-hi-86</th> +<th data-quarto-table-cell-role="th">AutoARIMA/TopDown_method-average_proportions-hi-88</th> +<th data-quarto-table-cell-role="th">AutoARIMA/TopDown_method-average_proportions-hi-90</th> +<th data-quarto-table-cell-role="th">AutoARIMA/TopDown_method-average_proportions-hi-92</th> +<th data-quarto-table-cell-role="th">AutoARIMA/TopDown_method-average_proportions-hi-94</th> +<th data-quarto-table-cell-role="th">AutoARIMA/TopDown_method-average_proportions-hi-96</th> +<th data-quarto-table-cell-role="th">AutoARIMA/TopDown_method-average_proportions-hi-98</th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td data-quarto-table-cell-role="th">0</td> +<td>80750.389920</td> +<td>80750.389920</td> +<td>80750.389920</td> +<td>82299.061781</td> +<td>82299.061781</td> +<td>82299.061781</td> +<td>82600.022716</td> +<td>82600.022716</td> +<td>82600.022716</td> +<td>82763.007090</td> +<td>...</td> +<td>88248.624229</td> +<td>88248.624229</td> +<td>88248.624229</td> +<td>88248.624229</td> +<td>88384.153447</td> +<td>90507.444522</td> +<td>90507.444522</td> +<td>90507.444522</td> +<td>90507.444522</td> +<td>90507.444522</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">1</td> +<td>61825.843210</td> +<td>61825.843210</td> +<td>61825.843210</td> +<td>61825.843210</td> +<td>61825.843210</td> +<td>61825.843210</td> +<td>63374.515072</td> +<td>63374.515072</td> +<td>63374.515072</td> +<td>63374.515072</td> +<td>...</td> +<td>68196.499405</td> +<td>68196.499405</td> +<td>68286.705654</td> +<td>69324.077520</td> +<td>69324.077520</td> +<td>69437.018534</td> +<td>71582.897812</td> +<td>71582.897812</td> +<td>71582.897812</td> +<td>71582.897812</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">2</td> +<td>68249.624404</td> +<td>68249.624404</td> +<td>68249.624404</td> +<td>68249.624404</td> +<td>69798.296266</td> +<td>69798.296266</td> +<td>69798.296266</td> +<td>69798.296266</td> +<td>69798.296266</td> +<td>69798.296266</td> +<td>...</td> +<td>74620.280598</td> +<td>74620.280598</td> +<td>74620.280598</td> +<td>74699.211067</td> +<td>75747.858714</td> +<td>75747.858714</td> +<td>75747.858714</td> +<td>75815.623322</td> +<td>78006.679006</td> +<td>78006.679006</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">3</td> +<td>67456.030661</td> +<td>67456.030661</td> +<td>67456.030661</td> +<td>67456.030661</td> +<td>69004.702523</td> +<td>69004.702523</td> +<td>69004.702523</td> +<td>69004.702523</td> +<td>69004.702523</td> +<td>69305.663457</td> +<td>...</td> +<td>73939.444667</td> +<td>74954.264971</td> +<td>74954.264971</td> +<td>74954.264971</td> +<td>74954.264971</td> +<td>74954.264971</td> +<td>75044.617782</td> +<td>77213.085263</td> +<td>77213.085263</td> +<td>77213.085263</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">4</td> +<td>80371.819611</td> +<td>80371.819611</td> +<td>80371.819611</td> +<td>80371.819611</td> +<td>80371.819611</td> +<td>81827.571161</td> +<td>81920.491472</td> +<td>81920.491472</td> +<td>81920.491472</td> +<td>81920.491472</td> +<td>...</td> +<td>87870.053920</td> +<td>87870.053920</td> +<td>87870.053920</td> +<td>87870.053920</td> +<td>88005.583138</td> +<td>90128.874213</td> +<td>90128.874213</td> +<td>90128.874213</td> +<td>90128.874213</td> +<td>90128.874213</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +<td>...</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">7115</td> +<td>132.959504</td> +<td>132.959504</td> +<td>132.959504</td> +<td>132.959504</td> +<td>132.959504</td> +<td>135.828870</td> +<td>136.012021</td> +<td>136.012021</td> +<td>136.012021</td> +<td>136.545910</td> +<td>...</td> +<td>147.738932</td> +<td>147.738932</td> +<td>147.738932</td> +<td>152.191189</td> +<td>152.191189</td> +<td>152.191189</td> +<td>152.191189</td> +<td>152.191189</td> +<td>152.191189</td> +<td>152.191189</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">7116</td> +<td>158.417227</td> +<td>158.417227</td> +<td>158.417227</td> +<td>158.417227</td> +<td>158.417227</td> +<td>161.469743</td> +<td>161.469743</td> +<td>161.469743</td> +<td>161.469743</td> +<td>162.062953</td> +<td>...</td> +<td>170.974136</td> +<td>171.174163</td> +<td>173.196654</td> +<td>173.196654</td> +<td>173.196654</td> +<td>173.419267</td> +<td>177.648912</td> +<td>177.648912</td> +<td>177.648912</td> +<td>177.648912</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">7117</td> +<td>122.066765</td> +<td>122.066765</td> +<td>125.119281</td> +<td>125.119281</td> +<td>125.119281</td> +<td>125.119281</td> +<td>125.712492</td> +<td>125.712492</td> +<td>125.712492</td> +<td>125.712492</td> +<td>...</td> +<td>134.623675</td> +<td>134.623675</td> +<td>134.801476</td> +<td>136.846192</td> +<td>136.846192</td> +<td>136.846192</td> +<td>137.024283</td> +<td>141.298450</td> +<td>141.298450</td> +<td>141.298450</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">7118</td> +<td>134.467576</td> +<td>134.467576</td> +<td>134.467576</td> +<td>134.467576</td> +<td>137.520093</td> +<td>137.520093</td> +<td>137.520093</td> +<td>137.520093</td> +<td>138.113303</td> +<td>138.113303</td> +<td>...</td> +<td>145.762241</td> +<td>145.875843</td> +<td>147.202288</td> +<td>149.247004</td> +<td>149.247004</td> +<td>149.247004</td> +<td>149.425094</td> +<td>153.699262</td> +<td>153.699262</td> +<td>153.699262</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">7119</td> +<td>135.996894</td> +<td>136.027420</td> +<td>136.027420</td> +<td>136.027420</td> +<td>136.027420</td> +<td>136.027420</td> +<td>136.027420</td> +<td>136.573173</td> +<td>136.620630</td> +<td>136.620630</td> +<td>...</td> +<td>145.531813</td> +<td>145.531813</td> +<td>145.709614</td> +<td>147.754331</td> +<td>147.754331</td> +<td>147.754331</td> +<td>147.932421</td> +<td>152.206588</td> +<td>152.206588</td> +<td>152.206588</td> +</tr> +</tbody> +</table> + +<p>7120 rows Ć 100 columns</p> +</div> +</div> +</div> +</section> +<section id="evaluation" class="level2"> +<h2 class="anchored" data-anchor-id="evaluation">4. Evaluation</h2> +<div class="cell"> +<div class="sourceCode cell-code" id="cb19"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb19-1"><a href="#cb19-1" aria-hidden="true" tabindex="-1"></a><span class="cf">with</span> CodeTimer(<span class="st">'Evaluate Models CRPS '</span>, verbose):</span> +<span id="cb19-2"><a href="#cb19-2" aria-hidden="true" tabindex="-1"></a> crps_results <span class="op">=</span> {<span class="st">'Dataset'</span>: [dataset] <span class="op">*</span> <span class="bu">len</span>([<span class="st">'Overall'</span>] <span class="op">+</span> <span class="bu">list</span>(tags.keys())),</span> +<span id="cb19-3"><a href="#cb19-3" aria-hidden="true" tabindex="-1"></a> <span class="st">'Level'</span>: [<span class="st">'Overall'</span>] <span class="op">+</span> <span class="bu">list</span>(tags.keys()),}</span> +<span id="cb19-4"><a href="#cb19-4" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb19-5"><a href="#cb19-5" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> model <span class="kw">in</span> hrec.level_names.keys():</span> +<span id="cb19-6"><a href="#cb19-6" aria-hidden="true" tabindex="-1"></a> crps_results[model] <span class="op">=</span> []</span> +<span id="cb19-7"><a href="#cb19-7" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> level <span class="kw">in</span> crps_results[<span class="st">'Level'</span>]:</span> +<span id="cb19-8"><a href="#cb19-8" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> level<span class="op">==</span><span class="st">'Overall'</span>:</span> +<span id="cb19-9"><a href="#cb19-9" aria-hidden="true" tabindex="-1"></a> row_idxs <span class="op">=</span> np.arange(<span class="bu">len</span>(S_df))</span> +<span id="cb19-10"><a href="#cb19-10" aria-hidden="true" tabindex="-1"></a> <span class="cf">else</span>:</span> +<span id="cb19-11"><a href="#cb19-11" aria-hidden="true" tabindex="-1"></a> row_idxs <span class="op">=</span> S_df.index.get_indexer(tags[level])</span> +<span id="cb19-12"><a href="#cb19-12" aria-hidden="true" tabindex="-1"></a> col_idxs <span class="op">=</span> model_columns.get_indexer(hrec.level_names[model])</span> +<span id="cb19-13"><a href="#cb19-13" aria-hidden="true" tabindex="-1"></a> _y <span class="op">=</span> y_test[row_idxs,:]</span> +<span id="cb19-14"><a href="#cb19-14" aria-hidden="true" tabindex="-1"></a> _y_rec_seeds <span class="op">=</span> y_rec[:,row_idxs,:,:][:,:,:,col_idxs]</span> +<span id="cb19-15"><a href="#cb19-15" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb19-16"><a href="#cb19-16" aria-hidden="true" tabindex="-1"></a> level_model_crps <span class="op">=</span> []</span> +<span id="cb19-17"><a href="#cb19-17" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> seed_idx <span class="kw">in</span> <span class="bu">range</span>(y_rec.shape[<span class="dv">0</span>]):</span> +<span id="cb19-18"><a href="#cb19-18" aria-hidden="true" tabindex="-1"></a> _y_rec <span class="op">=</span> _y_rec_seeds[seed_idx,:,:,:]</span> +<span id="cb19-19"><a href="#cb19-19" aria-hidden="true" tabindex="-1"></a> level_model_crps.append(scaled_crps(y<span class="op">=</span>_y, y_hat<span class="op">=</span>_y_rec,</span> +<span id="cb19-20"><a href="#cb19-20" aria-hidden="true" tabindex="-1"></a> quantiles<span class="op">=</span>QUANTILES))</span> +<span id="cb19-21"><a href="#cb19-21" aria-hidden="true" tabindex="-1"></a> level_model_crps <span class="op">=</span> <span class="ss">f'</span><span class="sc">{</span>np<span class="sc">.</span>mean(level_model_crps)<span class="sc">:.4f}</span><span class="ss">Ā±</span><span class="sc">{</span>(<span class="fl">1.96</span> <span class="op">*</span> np.std(level_model_crps))<span class="sc">:.4f}</span><span class="ss">'</span></span> +<span id="cb19-22"><a href="#cb19-22" aria-hidden="true" tabindex="-1"></a> crps_results[model].append(level_model_crps)</span> +<span id="cb19-23"><a href="#cb19-23" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb19-24"><a href="#cb19-24" aria-hidden="true" tabindex="-1"></a> crps_results <span class="op">=</span> pd.DataFrame(crps_results)</span> +<span id="cb19-25"><a href="#cb19-25" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb19-26"><a href="#cb19-26" aria-hidden="true" tabindex="-1"></a>crps_results</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-stdout"> +<pre><code>Code block 'Evaluate Models CRPS ' took: 1.13514 seconds</code></pre> +</div> +<div class="cell-output cell-output-display"> +<div> + + +<table class="dataframe table table-sm table-striped small" data-quarto-postprocess="true" data-border="1"> +<thead> +<tr class="header"> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th">Dataset</th> +<th data-quarto-table-cell-role="th">Level</th> +<th data-quarto-table-cell-role="th">AutoARIMA/BottomUp</th> +<th data-quarto-table-cell-role="th">AutoARIMA/TopDown_method-average_proportions</th> +<th data-quarto-table-cell-role="th">AutoARIMA/TopDown_method-proportion_averages</th> +<th data-quarto-table-cell-role="th">AutoARIMA/MinTrace_method-ols</th> +<th data-quarto-table-cell-role="th">AutoARIMA/MinTrace_method-wls_var</th> +<th data-quarto-table-cell-role="th">AutoARIMA/MinTrace_method-mint_shrink</th> +<th data-quarto-table-cell-role="th">AutoARIMA/ERM_method-closed_lambda_reg-0.01</th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td data-quarto-table-cell-role="th">0</td> +<td>TourismSmall</td> +<td>Overall</td> +<td>0.0895Ā±0.0012</td> +<td>0.1195Ā±0.0008</td> +<td>0.1197Ā±0.0008</td> +<td>0.0927Ā±0.0010</td> +<td>0.0890Ā±0.0010</td> +<td>0.0898Ā±0.0009</td> +<td>0.1116Ā±0.0015</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">1</td> +<td>TourismSmall</td> +<td>Country</td> +<td>0.0481Ā±0.0016</td> +<td>0.0479Ā±0.0011</td> +<td>0.0479Ā±0.0011</td> +<td>0.0504Ā±0.0010</td> +<td>0.0510Ā±0.0011</td> +<td>0.0512Ā±0.0011</td> +<td>0.0525Ā±0.0015</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">2</td> +<td>TourismSmall</td> +<td>Country/Purpose</td> +<td>0.0699Ā±0.0016</td> +<td>0.0928Ā±0.0009</td> +<td>0.0931Ā±0.0009</td> +<td>0.0804Ā±0.0012</td> +<td>0.0724Ā±0.0012</td> +<td>0.0741Ā±0.0012</td> +<td>0.0927Ā±0.0015</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">3</td> +<td>TourismSmall</td> +<td>Country/Purpose/State</td> +<td>0.1085Ā±0.0011</td> +<td>0.1575Ā±0.0009</td> +<td>0.1579Ā±0.0009</td> +<td>0.1082Ā±0.0011</td> +<td>0.1043Ā±0.0009</td> +<td>0.1049Ā±0.0008</td> +<td>0.1325Ā±0.0018</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">4</td> +<td>TourismSmall</td> +<td>Country/Purpose/State/CityNonCity</td> +<td>0.1316Ā±0.0012</td> +<td>0.1799Ā±0.0008</td> +<td>0.1800Ā±0.0008</td> +<td>0.1319Ā±0.0013</td> +<td>0.1282Ā±0.0011</td> +<td>0.1290Ā±0.0010</td> +<td>0.1685Ā±0.0029</td> +</tr> +</tbody> +</table> + +</div> +</div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb21"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb21-1"><a href="#cb21-1" aria-hidden="true" tabindex="-1"></a><span class="cf">with</span> CodeTimer(<span class="st">'Evaluate Models MSSE '</span>, verbose):</span> +<span id="cb21-2"><a href="#cb21-2" aria-hidden="true" tabindex="-1"></a> msse_results <span class="op">=</span> {<span class="st">'Dataset'</span>: [dataset] <span class="op">*</span> <span class="bu">len</span>([<span class="st">'Overall'</span>] <span class="op">+</span> <span class="bu">list</span>(tags.keys())),</span> +<span id="cb21-3"><a href="#cb21-3" aria-hidden="true" tabindex="-1"></a> <span class="st">'Level'</span>: [<span class="st">'Overall'</span>] <span class="op">+</span> <span class="bu">list</span>(tags.keys()),}</span> +<span id="cb21-4"><a href="#cb21-4" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> model <span class="kw">in</span> hrec.level_names.keys():</span> +<span id="cb21-5"><a href="#cb21-5" aria-hidden="true" tabindex="-1"></a> msse_results[model] <span class="op">=</span> []</span> +<span id="cb21-6"><a href="#cb21-6" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> level <span class="kw">in</span> msse_results[<span class="st">'Level'</span>]:</span> +<span id="cb21-7"><a href="#cb21-7" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> level<span class="op">==</span><span class="st">'Overall'</span>:</span> +<span id="cb21-8"><a href="#cb21-8" aria-hidden="true" tabindex="-1"></a> row_idxs <span class="op">=</span> np.arange(<span class="bu">len</span>(S_df))</span> +<span id="cb21-9"><a href="#cb21-9" aria-hidden="true" tabindex="-1"></a> <span class="cf">else</span>:</span> +<span id="cb21-10"><a href="#cb21-10" aria-hidden="true" tabindex="-1"></a> row_idxs <span class="op">=</span> S_df.index.get_indexer(tags[level])</span> +<span id="cb21-11"><a href="#cb21-11" aria-hidden="true" tabindex="-1"></a> col_idx <span class="op">=</span> model_columns.get_loc(model)</span> +<span id="cb21-12"><a href="#cb21-12" aria-hidden="true" tabindex="-1"></a> _y <span class="op">=</span> y_test[row_idxs,:]</span> +<span id="cb21-13"><a href="#cb21-13" aria-hidden="true" tabindex="-1"></a> _y_train <span class="op">=</span> y_train[row_idxs,:]</span> +<span id="cb21-14"><a href="#cb21-14" aria-hidden="true" tabindex="-1"></a> _y_hat_seeds <span class="op">=</span> y_rec[:,row_idxs,:,:][:,:,:,col_idx]</span> +<span id="cb21-15"><a href="#cb21-15" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb21-16"><a href="#cb21-16" aria-hidden="true" tabindex="-1"></a> level_model_msse <span class="op">=</span> []</span> +<span id="cb21-17"><a href="#cb21-17" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> seed_idx <span class="kw">in</span> <span class="bu">range</span>(y_rec.shape[<span class="dv">0</span>]):</span> +<span id="cb21-18"><a href="#cb21-18" aria-hidden="true" tabindex="-1"></a> _y_hat <span class="op">=</span> _y_hat_seeds[seed_idx,:,:]</span> +<span id="cb21-19"><a href="#cb21-19" aria-hidden="true" tabindex="-1"></a> level_model_msse.append(msse(y<span class="op">=</span>_y, y_hat<span class="op">=</span>_y_hat, y_train<span class="op">=</span>_y_train))</span> +<span id="cb21-20"><a href="#cb21-20" aria-hidden="true" tabindex="-1"></a> <span class="co">#level_model_msse = f'{np.mean(level_model_msse):.4f}Ā±{(1.96 * np.std(level_model_msse)):.4f}'</span></span> +<span id="cb21-21"><a href="#cb21-21" aria-hidden="true" tabindex="-1"></a> level_model_msse <span class="op">=</span> <span class="ss">f'</span><span class="sc">{</span>np<span class="sc">.</span>mean(level_model_msse)<span class="sc">:.4f}</span><span class="ss">'</span></span> +<span id="cb21-22"><a href="#cb21-22" aria-hidden="true" tabindex="-1"></a> msse_results[model].append(level_model_msse)</span> +<span id="cb21-23"><a href="#cb21-23" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb21-24"><a href="#cb21-24" aria-hidden="true" tabindex="-1"></a> msse_results <span class="op">=</span> pd.DataFrame(msse_results)</span> +<span id="cb21-25"><a href="#cb21-25" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb21-26"><a href="#cb21-26" aria-hidden="true" tabindex="-1"></a>msse_results</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-stdout"> +<pre><code>Code block 'Evaluate Models MSSE ' took: 0.73303 seconds</code></pre> +</div> +<div class="cell-output cell-output-display"> +<div> + + +<table class="dataframe table table-sm table-striped small" data-quarto-postprocess="true" data-border="1"> +<thead> +<tr class="header"> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th">Dataset</th> +<th data-quarto-table-cell-role="th">Level</th> +<th data-quarto-table-cell-role="th">AutoARIMA/BottomUp</th> +<th data-quarto-table-cell-role="th">AutoARIMA/TopDown_method-average_proportions</th> +<th data-quarto-table-cell-role="th">AutoARIMA/TopDown_method-proportion_averages</th> +<th data-quarto-table-cell-role="th">AutoARIMA/MinTrace_method-ols</th> +<th data-quarto-table-cell-role="th">AutoARIMA/MinTrace_method-wls_var</th> +<th data-quarto-table-cell-role="th">AutoARIMA/MinTrace_method-mint_shrink</th> +<th data-quarto-table-cell-role="th">AutoARIMA/ERM_method-closed_lambda_reg-0.01</th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td data-quarto-table-cell-role="th">0</td> +<td>TourismSmall</td> +<td>Overall</td> +<td>0.2530</td> +<td>0.3628</td> +<td>0.3649</td> +<td>0.3039</td> +<td>0.2789</td> +<td>0.2822</td> +<td>0.3942</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">1</td> +<td>TourismSmall</td> +<td>Country</td> +<td>0.2564</td> +<td>0.3180</td> +<td>0.3180</td> +<td>0.3522</td> +<td>0.3381</td> +<td>0.3394</td> +<td>0.4117</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">2</td> +<td>TourismSmall</td> +<td>Country/Purpose</td> +<td>0.2018</td> +<td>0.3178</td> +<td>0.3203</td> +<td>0.2557</td> +<td>0.2122</td> +<td>0.2175</td> +<td>0.3346</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">3</td> +<td>TourismSmall</td> +<td>Country/Purpose/State</td> +<td>0.3231</td> +<td>0.5077</td> +<td>0.5114</td> +<td>0.2943</td> +<td>0.2858</td> +<td>0.2890</td> +<td>0.4534</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">4</td> +<td>TourismSmall</td> +<td>Country/Purpose/State/CityNonCity</td> +<td>0.3423</td> +<td>0.5047</td> +<td>0.5099</td> +<td>0.3238</td> +<td>0.3083</td> +<td>0.3115</td> +<td>0.4791</td> +</tr> +</tbody> +</table> + +</div> +</div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb23"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb23-1"><a href="#cb23-1" aria-hidden="true" tabindex="-1"></a><span class="cf">with</span> CodeTimer(<span class="st">'Evaluate Models EScore'</span>, verbose):</span> +<span id="cb23-2"><a href="#cb23-2" aria-hidden="true" tabindex="-1"></a> energy_results <span class="op">=</span> {<span class="st">'Dataset'</span>: [dataset] <span class="op">*</span> <span class="bu">len</span>([<span class="st">'Overall'</span>] <span class="op">+</span> <span class="bu">list</span>(tags.keys())),</span> +<span id="cb23-3"><a href="#cb23-3" aria-hidden="true" tabindex="-1"></a> <span class="st">'Level'</span>: [<span class="st">'Overall'</span>] <span class="op">+</span> <span class="bu">list</span>(tags.keys()),}</span> +<span id="cb23-4"><a href="#cb23-4" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> model <span class="kw">in</span> hrec.sample_names.keys():</span> +<span id="cb23-5"><a href="#cb23-5" aria-hidden="true" tabindex="-1"></a> energy_results[model] <span class="op">=</span> []</span> +<span id="cb23-6"><a href="#cb23-6" aria-hidden="true" tabindex="-1"></a> <span class="cf">for</span> level <span class="kw">in</span> energy_results[<span class="st">'Level'</span>]:</span> +<span id="cb23-7"><a href="#cb23-7" aria-hidden="true" tabindex="-1"></a> <span class="cf">if</span> level<span class="op">==</span><span class="st">'Overall'</span>:</span> +<span id="cb23-8"><a href="#cb23-8" aria-hidden="true" tabindex="-1"></a> row_idxs <span class="op">=</span> np.arange(<span class="bu">len</span>(S_df))</span> +<span id="cb23-9"><a href="#cb23-9" aria-hidden="true" tabindex="-1"></a> <span class="cf">else</span>:</span> +<span id="cb23-10"><a href="#cb23-10" aria-hidden="true" tabindex="-1"></a> row_idxs <span class="op">=</span> S_df.index.get_indexer(tags[level])</span> +<span id="cb23-11"><a href="#cb23-11" aria-hidden="true" tabindex="-1"></a> col_idxs <span class="op">=</span> model_columns.get_indexer(hrec.sample_names[model])</span> +<span id="cb23-12"><a href="#cb23-12" aria-hidden="true" tabindex="-1"></a> _y <span class="op">=</span> y_test[row_idxs,:]</span> +<span id="cb23-13"><a href="#cb23-13" aria-hidden="true" tabindex="-1"></a> _y_sample1 <span class="op">=</span> y_rec[<span class="dv">0</span>,row_idxs,:,:][:,:,col_idxs[:<span class="bu">len</span>(col_idxs)<span class="op">//</span><span class="dv">2</span>]]</span> +<span id="cb23-14"><a href="#cb23-14" aria-hidden="true" tabindex="-1"></a> _y_sample2 <span class="op">=</span> y_rec[<span class="dv">0</span>,row_idxs,:,:][:,:,col_idxs[<span class="bu">len</span>(col_idxs)<span class="op">//</span><span class="dv">2</span>:]]</span> +<span id="cb23-15"><a href="#cb23-15" aria-hidden="true" tabindex="-1"></a> level_model_energy <span class="op">=</span> energy_score(y<span class="op">=</span>_y, </span> +<span id="cb23-16"><a href="#cb23-16" aria-hidden="true" tabindex="-1"></a> y_sample1<span class="op">=</span>_y_sample1,</span> +<span id="cb23-17"><a href="#cb23-17" aria-hidden="true" tabindex="-1"></a> y_sample2<span class="op">=</span>_y_sample2,</span> +<span id="cb23-18"><a href="#cb23-18" aria-hidden="true" tabindex="-1"></a> beta<span class="op">=</span><span class="dv">2</span>)</span> +<span id="cb23-19"><a href="#cb23-19" aria-hidden="true" tabindex="-1"></a> energy_results[model].append(level_model_energy)</span> +<span id="cb23-20"><a href="#cb23-20" aria-hidden="true" tabindex="-1"></a> energy_results <span class="op">=</span> pd.DataFrame(energy_results)</span> +<span id="cb23-21"><a href="#cb23-21" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb23-22"><a href="#cb23-22" aria-hidden="true" tabindex="-1"></a>energy_results</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-stdout"> +<pre><code>Code block 'Evaluate Models EScore' took: 0.19443 seconds</code></pre> +</div> +<div class="cell-output cell-output-display"> +<div> + + +<table class="dataframe table table-sm table-striped small" data-quarto-postprocess="true" data-border="1"> +<thead> +<tr class="header"> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th">Dataset</th> +<th data-quarto-table-cell-role="th">Level</th> +<th data-quarto-table-cell-role="th">AutoARIMA/BottomUp</th> +<th data-quarto-table-cell-role="th">AutoARIMA/TopDown_method-average_proportions</th> +<th data-quarto-table-cell-role="th">AutoARIMA/TopDown_method-proportion_averages</th> +<th data-quarto-table-cell-role="th">AutoARIMA/MinTrace_method-ols</th> +<th data-quarto-table-cell-role="th">AutoARIMA/MinTrace_method-wls_var</th> +<th data-quarto-table-cell-role="th">AutoARIMA/MinTrace_method-mint_shrink</th> +<th data-quarto-table-cell-role="th">AutoARIMA/ERM_method-closed_lambda_reg-0.01</th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td data-quarto-table-cell-role="th">0</td> +<td>TourismSmall</td> +<td>Overall</td> +<td>6.874103e+07</td> +<td>7.917294e+07</td> +<td>7.962361e+07</td> +<td>6.930268e+07</td> +<td>6.914837e+07</td> +<td>6.955018e+07</td> +<td>8.235776e+07</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">1</td> +<td>TourismSmall</td> +<td>Country</td> +<td>3.292999e+07</td> +<td>2.757131e+07</td> +<td>2.757129e+07</td> +<td>3.081254e+07</td> +<td>3.392861e+07</td> +<td>3.353851e+07</td> +<td>3.350023e+07</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">2</td> +<td>TourismSmall</td> +<td>Country/Purpose</td> +<td>1.894485e+07</td> +<td>2.661024e+07</td> +<td>2.683828e+07</td> +<td>2.218952e+07</td> +<td>1.932895e+07</td> +<td>1.984161e+07</td> +<td>2.681792e+07</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">3</td> +<td>TourismSmall</td> +<td>Country/Purpose/State</td> +<td>9.393103e+06</td> +<td>1.408613e+07</td> +<td>1.419471e+07</td> +<td>9.016056e+06</td> +<td>8.778983e+06</td> +<td>8.928542e+06</td> +<td>1.211747e+07</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">4</td> +<td>TourismSmall</td> +<td>Country/Purpose/State/CityNonCity</td> +<td>7.473085e+06</td> +<td>1.090527e+07</td> +<td>1.101934e+07</td> +<td>7.284562e+06</td> +<td>7.111832e+06</td> +<td>7.241519e+06</td> +<td>9.922145e+06</td> +</tr> +</tbody> +</table> + +</div> +</div> +</div> +</section> +<section id="references" class="level2"> +<h2 class="anchored" data-anchor-id="references">References</h2> +<ul> +<li><a href="https://proceedings.mlr.press/v139/rangapuram21a.html">Syama Sundar Rangapuram, Lucien D Werner, Konstantinos Benidis, Pedro Mercado, Jan Gasthaus, Tim Januschowski. (2021). "End-to-End Learning of Coherent Probabilistic Forecasts for Hierarchical Time Series". Proceedings of the 38th International Conference on Machine Learning (ICML).</a></li> +<li><a href="https://arxiv.org/pdf/2110.13179.pdf">Kin G. Olivares, O. Nganba Meetei, Ruijun Ma, Rohan Reddy, Mengfei Cao, Lee Dicker (2022). āProbabilistic Hierarchical Forecasting with Deep Poisson Mixturesā. Submitted to the International Journal Forecasting, Working paper available at arxiv.</a></li> +</ul> + + +</section> + +<p>If you find the code useful, please ā us on <a href="https://github.com/nixtla/hierarchicalforecast">Github</a></p></main> <!-- /main --> +<script id="quarto-html-after-body" type="application/javascript"> +window.document.addEventListener("DOMContentLoaded", function (event) { + const toggleBodyColorMode = (bsSheetEl) => { + const mode = bsSheetEl.getAttribute("data-mode"); + const bodyEl = window.document.querySelector("body"); + if (mode === "dark") { + bodyEl.classList.add("quarto-dark"); + bodyEl.classList.remove("quarto-light"); + } else { + bodyEl.classList.add("quarto-light"); + bodyEl.classList.remove("quarto-dark"); + } + } + const toggleBodyColorPrimary = () => { + const bsSheetEl = window.document.querySelector("link#quarto-bootstrap"); + if (bsSheetEl) { + toggleBodyColorMode(bsSheetEl); + } + } + toggleBodyColorPrimary(); + const icon = "ī§"; + const anchorJS = new window.AnchorJS(); + anchorJS.options = { + placement: 'right', + icon: icon + }; + anchorJS.add('.anchored'); + const isCodeAnnotation = (el) => { + for (const clz of el.classList) { + if (clz.startsWith('code-annotation-')) { + return true; + } + } + return false; + } + const clipboard = new window.ClipboardJS('.code-copy-button', { + text: function(trigger) { + const codeEl = trigger.previousElementSibling.cloneNode(true); + for (const childEl of codeEl.children) { + if (isCodeAnnotation(childEl)) { + childEl.remove(); + } + } + return codeEl.innerText; + } + }); + clipboard.on('success', function(e) { + // button target + const button = e.trigger; + // don't keep focus + button.blur(); + // flash "checked" + button.classList.add('code-copy-button-checked'); + var currentTitle = button.getAttribute("title"); + button.setAttribute("title", "Copied!"); + let tooltip; + if (window.bootstrap) { + button.setAttribute("data-bs-toggle", "tooltip"); + button.setAttribute("data-bs-placement", "left"); + button.setAttribute("data-bs-title", "Copied!"); + tooltip = new bootstrap.Tooltip(button, + { trigger: "manual", + customClass: "code-copy-button-tooltip", + offset: [0, -8]}); + tooltip.show(); + } + setTimeout(function() { + if (tooltip) { + tooltip.hide(); + button.removeAttribute("data-bs-title"); + button.removeAttribute("data-bs-toggle"); + button.removeAttribute("data-bs-placement"); + } + button.setAttribute("title", currentTitle); + button.classList.remove('code-copy-button-checked'); + }, 1000); + // clear code selection + e.clearSelection(); + }); + function tippyHover(el, contentFn) { + const config = { + allowHTML: true, + content: contentFn, + maxWidth: 500, + delay: 100, + arrow: false, + appendTo: function(el) { + return el.parentElement; + }, + interactive: true, + interactiveBorder: 10, + theme: 'quarto', + placement: 'bottom-start' + }; + window.tippy(el, config); + } + const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]'); + for (var i=0; i<noterefs.length; i++) { + const ref = noterefs[i]; + tippyHover(ref, function() { + // use id or data attribute instead here + let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href'); + try { href = new URL(href).hash; } catch {} + const id = href.replace(/^#\/?/, ""); + const note = window.document.getElementById(id); + return note.innerHTML; + }); + } + let selectedAnnoteEl; + const selectorForAnnotation = ( cell, annotation) => { + let cellAttr = 'data-code-cell="' + cell + '"'; + let lineAttr = 'data-code-annotation="' + annotation + '"'; + const selector = 'span[' + cellAttr + '][' + lineAttr + ']'; + return selector; + } + const selectCodeLines = (annoteEl) => { + const doc = window.document; + const targetCell = annoteEl.getAttribute("data-target-cell"); + const targetAnnotation = annoteEl.getAttribute("data-target-annotation"); + const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation)); + const lines = annoteSpan.getAttribute("data-code-lines").split(","); + const lineIds = lines.map((line) => { + return targetCell + "-" + line; + }) + let top = null; + let height = null; + let parent = null; + if (lineIds.length > 0) { + //compute the position of the single el (top and bottom and make a div) + const el = window.document.getElementById(lineIds[0]); + top = el.offsetTop; + height = el.offsetHeight; + parent = el.parentElement.parentElement; + if (lineIds.length > 1) { + const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]); + const bottom = lastEl.offsetTop + lastEl.offsetHeight; + height = bottom - top; + } + if (top !== null && height !== null && parent !== null) { + // cook up a div (if necessary) and position it + let div = window.document.getElementById("code-annotation-line-highlight"); + if (div === null) { + div = window.document.createElement("div"); + div.setAttribute("id", "code-annotation-line-highlight"); + div.style.position = 'absolute'; + parent.appendChild(div); + } + div.style.top = top - 2 + "px"; + div.style.height = height + 4 + "px"; + let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter"); + if (gutterDiv === null) { + gutterDiv = window.document.createElement("div"); + gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter"); + gutterDiv.style.position = 'absolute'; + const codeCell = window.document.getElementById(targetCell); + const gutter = codeCell.querySelector('.code-annotation-gutter'); + gutter.appendChild(gutterDiv); + } + gutterDiv.style.top = top - 2 + "px"; + gutterDiv.style.height = height + 4 + "px"; + } + selectedAnnoteEl = annoteEl; + } + }; + const unselectCodeLines = () => { + const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"]; + elementsIds.forEach((elId) => { + const div = window.document.getElementById(elId); + if (div) { + div.remove(); + } + }); + selectedAnnoteEl = undefined; + }; + // Attach click handler to the DT + const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); + for (const annoteDlNode of annoteDls) { + annoteDlNode.addEventListener('click', (event) => { + const clickedEl = event.target; + if (clickedEl !== selectedAnnoteEl) { + unselectCodeLines(); + const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active'); + if (activeEl) { + activeEl.classList.remove('code-annotation-active'); + } + selectCodeLines(clickedEl); + clickedEl.classList.add('code-annotation-active'); + } else { + // Unselect the line + unselectCodeLines(); + clickedEl.classList.remove('code-annotation-active'); + } + }); + } + const findCites = (el) => { + const parentEl = el.parentElement; + if (parentEl) { + const cites = parentEl.dataset.cites; + if (cites) { + return { + el, + cites: cites.split(' ') + }; + } else { + return findCites(el.parentElement) + } + } else { + return undefined; + } + }; + var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]'); + for (var i=0; i<bibliorefs.length; i++) { + const ref = bibliorefs[i]; + const citeInfo = findCites(ref); + if (citeInfo) { + tippyHover(citeInfo.el, function() { + var popup = window.document.createElement('div'); + citeInfo.cites.forEach(function(cite) { + var citeDiv = window.document.createElement('div'); + citeDiv.classList.add('hanging-indent'); + citeDiv.classList.add('csl-entry'); + var biblioDiv = window.document.getElementById('ref-' + cite); + if (biblioDiv) { + citeDiv.innerHTML = biblioDiv.innerHTML; + } + popup.appendChild(citeDiv); + }); + return popup.innerHTML; + }); + } + } +}); +</script> +</div> <!-- /content --> + + + +</body></html> \ No newline at end of file diff --git a/examples/tourismsmall.html b/examples/tourismsmall.html new file mode 100644 index 00000000..5ffece01 --- /dev/null +++ b/examples/tourismsmall.html @@ -0,0 +1,1004 @@ +<!DOCTYPE html> +<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head> + +<meta charset="utf-8"> +<meta name="generator" content="quarto-1.3.450"> + +<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes"> + +<meta name="description" content="Minimal Example of Hierarchical Reconciliation"> + +<title>hierarchicalforecast - Reconciliation Quick Start</title> +<style> +code{white-space: pre-wrap;} +span.smallcaps{font-variant: small-caps;} +div.columns{display: flex; gap: min(4vw, 1.5em);} +div.column{flex: auto; overflow-x: auto;} +div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;} +ul.task-list{list-style: none;} +ul.task-list li input[type="checkbox"] { + width: 0.8em; + margin: 0 0.8em 0.2em -1em; /* quarto-specific, see https://github.com/quarto-dev/quarto-cli/issues/4556 */ + vertical-align: middle; +} +/* CSS for syntax highlighting */ +pre > code.sourceCode { white-space: pre; position: relative; } +pre > code.sourceCode > span { display: inline-block; line-height: 1.25; } +pre > code.sourceCode > span:empty { height: 1.2em; } +.sourceCode { overflow: visible; } +code.sourceCode > span { color: inherit; text-decoration: inherit; } +div.sourceCode { margin: 1em 0; } +pre.sourceCode { margin: 0; } +@media screen { +div.sourceCode { overflow: auto; } +} +@media print { +pre > code.sourceCode { white-space: pre-wrap; } +pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; } +} +pre.numberSource code + { counter-reset: source-line 0; } +pre.numberSource code > span + { position: relative; left: -4em; counter-increment: source-line; } +pre.numberSource code > span > a:first-child::before + { content: counter(source-line); + position: relative; left: -1em; text-align: right; vertical-align: baseline; + border: none; display: inline-block; + -webkit-touch-callout: none; -webkit-user-select: none; + -khtml-user-select: none; -moz-user-select: none; + -ms-user-select: none; user-select: none; + padding: 0 4px; width: 4em; + } +pre.numberSource { margin-left: 3em; padding-left: 4px; } +div.sourceCode + { } +@media screen { +pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; } +} +</style> + + +<script src="../site_libs/quarto-nav/quarto-nav.js"></script> +<script src="../site_libs/quarto-nav/headroom.min.js"></script> +<script src="../site_libs/clipboard/clipboard.min.js"></script> +<script src="../site_libs/quarto-search/autocomplete.umd.js"></script> +<script src="../site_libs/quarto-search/fuse.min.js"></script> +<script src="../site_libs/quarto-search/quarto-search.js"></script> +<meta name="quarto:offset" content="../"> +<link href="../favicon_png.png" rel="icon" type="image/png"> +<script src="../site_libs/quarto-html/quarto.js"></script> +<script src="../site_libs/quarto-html/popper.min.js"></script> +<script src="../site_libs/quarto-html/tippy.umd.min.js"></script> +<script src="../site_libs/quarto-html/anchor.min.js"></script> +<link href="../site_libs/quarto-html/tippy.css" rel="stylesheet"> +<link href="../site_libs/quarto-html/quarto-syntax-highlighting.css" rel="stylesheet" id="quarto-text-highlighting-styles"> +<script src="../site_libs/bootstrap/bootstrap.min.js"></script> +<link href="../site_libs/bootstrap/bootstrap-icons.css" rel="stylesheet"> +<link href="../site_libs/bootstrap/bootstrap.min.css" rel="stylesheet" id="quarto-bootstrap" data-mode="light"> +<script id="quarto-search-options" type="application/json">{ + "location": "navbar", + "copy-button": false, + "collapse-after": 3, + "panel-placement": "end", + "type": "overlay", + "limit": 20, + "language": { + "search-no-results-text": "No results", + "search-matching-documents-text": "matching documents", + "search-copy-link-title": "Copy link to search", + "search-hide-matches-text": "Hide additional matches", + "search-more-match-text": "more match in this document", + "search-more-matches-text": "more matches in this document", + "search-clear-button-title": "Clear", + "search-detached-cancel-button-title": "Cancel", + "search-submit-button-title": "Submit", + "search-label": "Search" + } +}</script> +<script async="" src="https://www.googletagmanager.com/gtag/js?id=G-NXJNCVR18L"></script> + +<script type="text/javascript"> + +window.dataLayer = window.dataLayer || []; +function gtag(){dataLayer.push(arguments);} +gtag('js', new Date()); +gtag('config', 'G-NXJNCVR18L', { 'anonymize_ip': true}); +</script> +<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.6/require.min.js" integrity="sha512-c3Nl8+7g4LMSTdrm621y7kf9v3SDPnhxLNhcjFJbKECVnmZHTdo+IRO05sNLTH/D3vA6u1X32ehoLC7WFVdheg==" crossorigin="anonymous"></script> +<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js" integrity="sha512-bLT0Qm9VnAYZDflyKcBaQ2gg0hSYNQrJ8RilYldYQ1FxQYoCLtUjuuRuZo+fjqhx/qtq/1itJ0C2ejDxltZVFg==" crossorigin="anonymous"></script> +<script type="application/javascript">define('jquery', [],function() {return window.jQuery;})</script> + + +<link rel="stylesheet" href="../styles.css"> +<meta property="og:title" content="hierarchicalforecast - Reconciliation Quick Start"> +<meta property="og:description" content="Minimal Example of Hierarchical Reconciliation"> +<meta property="og:image" content="https://colab.research.google.com/assets/colab-badge.svg"> +<meta property="og:site-name" content="hierarchicalforecast"> +<meta name="twitter:title" content="hierarchicalforecast - Reconciliation Quick Start"> +<meta name="twitter:description" content="Minimal Example of Hierarchical Reconciliation"> +<meta name="twitter:image" content="https://colab.research.google.com/assets/colab-badge.svg"> +<meta name="twitter:card" content="summary_large_image"> +</head> + +<body class="nav-sidebar floating nav-fixed"> + +<div id="quarto-search-results"></div> + <header id="quarto-header" class="headroom fixed-top"> + <nav class="navbar navbar-expand-lg navbar-dark "> + <div class="navbar-container container-fluid"> + <div class="navbar-brand-container"> + <a class="navbar-brand" href="../index.html"> + <span class="navbar-title">hierarchicalforecast</span> + </a> + </div> + <div id="quarto-search" class="" title="Search"></div> + <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + <span class="navbar-toggler-icon"></span> +</button> + <div class="collapse navbar-collapse" id="navbarCollapse"> + <ul class="navbar-nav navbar-nav-scroll me-auto"> + <li class="nav-item"> + <a class="nav-link active" href="../examples/tourismsmall.html" rel="" target="" aria-current="page"> + <span class="menu-text">Get Started</span></a> + </li> + <li class="nav-item dropdown "> + <a class="nav-link dropdown-toggle" href="#" id="nav-menu-nixtlaverse" role="button" data-bs-toggle="dropdown" aria-expanded="false" rel="" target=""> + <span class="menu-text">NixtlaVerse</span> + </a> + <ul class="dropdown-menu" aria-labelledby="nav-menu-nixtlaverse"> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/mlforecast" rel="" target=""> + <span class="dropdown-text">MLForecast š¤</span></a> + </li> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/neuralforecast" rel="" target=""> + <span class="dropdown-text">NeuralForecast š§ </span></a> + </li> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/statsforecast" rel="" target=""> + <span class="dropdown-text">StatsForecast ā”ļø</span></a> + </li> + </ul> + </li> + <li class="nav-item dropdown "> + <a class="nav-link dropdown-toggle" href="#" id="nav-menu-help" role="button" data-bs-toggle="dropdown" aria-expanded="false" rel="" target=""> + <span class="menu-text">Help</span> + </a> + <ul class="dropdown-menu" aria-labelledby="nav-menu-help"> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/hierarchicalforecast/issues/new/choose" rel="" target=""><i class="bi bi-bug" role="img"> +</i> + <span class="dropdown-text">Report an Issue</span></a> + </li> + <li> + <a class="dropdown-item" href="https://join.slack.com/t/nixtlacommunity/shared_invite/zt-1kd5m5db7-7OOfy0xVNf1PcvCiAPWvPw" rel="" target=""><i class="bi bi-chat-right-text" role="img"> +</i> + <span class="dropdown-text">Join our Slack</span></a> + </li> + </ul> + </li> +</ul> + <ul class="navbar-nav navbar-nav-scroll ms-auto"> + <li class="nav-item compact"> + <a class="nav-link" href="https://github.com/nixtla/hierarchicalforecast" rel="" target=""><i class="bi bi-github" role="img"> +</i> + <span class="menu-text"></span></a> + </li> + <li class="nav-item compact"> + <a class="nav-link" href="https://twitter.com/nixtlainc" rel="" target=""><i class="bi bi-twitter" role="img" aria-label="Nixtla Twitter"> +</i> + <span class="menu-text"></span></a> + </li> +</ul> + <div class="quarto-navbar-tools"> +</div> + </div> <!-- /navcollapse --> + </div> <!-- /container-fluid --> + </nav> + <nav class="quarto-secondary-nav"> + <div class="container-fluid d-flex"> + <button type="button" class="quarto-btn-toggle btn" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + <i class="bi bi-layout-text-sidebar-reverse"></i> + </button> + <nav class="quarto-page-breadcrumbs" aria-label="breadcrumb"><ol class="breadcrumb"><li class="breadcrumb-item"><a href="../examples/installation.html">Getting Started</a></li><li class="breadcrumb-item"><a href="../examples/tourismsmall.html">Reconciliation Quick Start</a></li></ol></nav> + <a class="flex-grow-1" role="button" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + </a> + </div> + </nav> +</header> +<!-- content --> +<div id="quarto-content" class="quarto-container page-columns page-rows-contents page-layout-article page-navbar"> +<!-- sidebar --> + <nav id="quarto-sidebar" class="sidebar collapse collapse-horizontal sidebar-navigation floating overflow-auto"> + <div class="sidebar-menu-container"> + <ul class="list-unstyled mt-1"> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../index.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Hierarchical Forecast š</span></a> + </div> +</li> + <li class="px-0"><hr class="sidebar-divider hi "></li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-1" aria-expanded="true"> + <span class="menu-text">Getting Started</span></a> + <a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-1" aria-expanded="true" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-1" class="collapse list-unstyled sidebar-section depth1 show"> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/installation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Install</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/tourismsmall.html" class="sidebar-item-text sidebar-link active"> + <span class="menu-text">Reconciliation Quick Start</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/introduction.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Introduction</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-2" aria-expanded="false"> + <span class="menu-text">Tutorials</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-2" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-2" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-3" aria-expanded="false"> + <span class="menu-text">Point Reconciliation</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-3" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-3" class="collapse list-unstyled sidebar-section depth2 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Geographical Aggregation (Tourism)</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australianprisonpopulation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Geographical Aggregation (Prison Population)</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/nonnegativereconciliation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Non-Negative MinTrace</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-4" aria-expanded="false"> + <span class="menu-text">Probabilistic Reconciliation</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-4" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-4" class="collapse list-unstyled sidebar-section depth2 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Normality</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism-bootstraped-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Bootstrap</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/australiandomestictourism-permbu-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">PERMBU</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/tourismlarge-evaluation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Probabilistic Forecast Evaluation</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-5" aria-expanded="false"> + <span class="menu-text">ML Forecast Reconciliation</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-5" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-5" class="collapse list-unstyled sidebar-section depth2 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/hierarchicalforecast-gluonts.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">GluonTS</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../examples/mlframeworksexample.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Neural/MLForecast</span></a> + </div> +</li> + </ul> + </li> + </ul> + </li> + <li class="sidebar-item"> + <span class="menu-text">Methods</span> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-6" aria-expanded="false"> + <span class="menu-text">API Reference</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-6" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-6" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../core.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Core </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../methods.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Reconciliation Methods </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../probabilistic_methods.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Probabilistic Methods </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../evaluation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Hierarchical Evaluation</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="../utils.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Aggregation/Visualization Utils</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-7" aria-expanded="false"> + <span class="menu-text">Community</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-7" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-7" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item"> + <span class="menu-text">Contributing</span> + </li> + </ul> + </li> + </ul> + </div> +</nav> +<div id="quarto-sidebar-glass" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass"></div> +<!-- margin-sidebar --> + <div id="quarto-margin-sidebar" class="sidebar margin-sidebar"> + <nav id="TOC" role="doc-toc" class="toc-active"> + <h2 id="toc-title">On this page</h2> + + <ul> + <li><a href="#libraries" id="toc-libraries" class="nav-link active" data-scroll-target="#libraries">1. Libraries</a></li> + <li><a href="#load-data" id="toc-load-data" class="nav-link" data-scroll-target="#load-data">2. Load Data</a></li> + <li><a href="#base-forecasts" id="toc-base-forecasts" class="nav-link" data-scroll-target="#base-forecasts">3. Base forecasts</a></li> + <li><a href="#hierarchical-reconciliation" id="toc-hierarchical-reconciliation" class="nav-link" data-scroll-target="#hierarchical-reconciliation">4. Hierarchical reconciliation</a></li> + <li><a href="#evaluation" id="toc-evaluation" class="nav-link" data-scroll-target="#evaluation">5. Evaluation</a> + <ul class="collapse"> + <li><a href="#references" id="toc-references" class="nav-link" data-scroll-target="#references">References</a></li> + </ul></li> + </ul> +<div class="toc-actions"><div><i class="bi bi-github"></i></div><div class="action-links"><p><a href="https://github.com/Nixtla/hierarchicalforecast/issues/new" class="toc-action">Report an issue</a></p></div></div></nav> + </div> +<!-- main --> +<main class="content" id="quarto-document-content"> + +<header id="title-block-header" class="quarto-title-block default"> +<div class="quarto-title"> +<h1 class="title">Reconciliation Quick Start</h1> +</div> + +<div> + <div class="description"> + Minimal Example of Hierarchical Reconciliation + </div> +</div> + + +<div class="quarto-title-meta"> + + + + + </div> + + +</header> + +<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! --> +<p>Large collections of time series organized into structures at different aggregation levels often require their forecasts to follow their aggregation constraints, which poses the challenge of creating novel algorithms capable of coherent forecasts.</p> +<p>The <code>HierarchicalForecast</code> package provides a wide collection of Python implementations of hierarchical forecasting algorithms that follow classic hierarchical reconciliation.</p> +<p>In this notebook we will show how to use the <code>StatsForecast</code> library to produce base forecasts, and use <code>HierarchicalForecast</code> package to perform hierarchical reconciliation.</p> +<p>You can run these experiments using CPU or GPU with Google Colab.</p> +<p><a href="https://colab.research.google.com/github/Nixtla/hierarchicalforecast/blob/main/nbs/examples/TourismSmall.ipynb" target="_parent"><img src="https://colab.research.google.com/assets/colab-badge.svg" alt="Open In Colab"></a></p> +<section id="libraries" class="level2"> +<h2 class="anchored" data-anchor-id="libraries">1. Libraries</h2> +<div class="cell"> +<div class="sourceCode cell-code" id="cb1"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a><span class="op">!</span>pip install hierarchicalforecast</span> +<span id="cb1-2"><a href="#cb1-2" aria-hidden="true" tabindex="-1"></a><span class="op">!</span>pip install <span class="op">-</span>U numba statsforecast datasetsforecast</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +</section> +<section id="load-data" class="level2"> +<h2 class="anchored" data-anchor-id="load-data">2. Load Data</h2> +<p>In this example we will use the <code>TourismSmall</code> dataset. The following cell gets the time series for the different levels in the hierarchy, the summing matrix <code>S</code> which recovers the full dataset from the bottom level hierarchy and the indices of each hierarchy denoted by <code>tags</code>.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb2"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> numpy <span class="im">as</span> np</span> +<span id="cb2-2"><a href="#cb2-2" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> pandas <span class="im">as</span> pd</span> +<span id="cb2-3"><a href="#cb2-3" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb2-4"><a href="#cb2-4" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> datasetsforecast.hierarchical <span class="im">import</span> HierarchicalData</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb3"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a>Y_df, S_df, tags <span class="op">=</span> HierarchicalData.load(<span class="st">'./data'</span>, <span class="st">'TourismSmall'</span>)</span> +<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a>Y_df[<span class="st">'ds'</span>] <span class="op">=</span> pd.to_datetime(Y_df[<span class="st">'ds'</span>])</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb4"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a>Y_df.head()</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<div> + + +<table class="dataframe table table-sm table-striped small" data-quarto-postprocess="true" data-border="1"> +<thead> +<tr class="header"> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th">unique_id</th> +<th data-quarto-table-cell-role="th">ds</th> +<th data-quarto-table-cell-role="th">y</th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td data-quarto-table-cell-role="th">0</td> +<td>total</td> +<td>1998-03-31</td> +<td>84503</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">1</td> +<td>total</td> +<td>1998-06-30</td> +<td>65312</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">2</td> +<td>total</td> +<td>1998-09-30</td> +<td>72753</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">3</td> +<td>total</td> +<td>1998-12-31</td> +<td>70880</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">4</td> +<td>total</td> +<td>1999-03-31</td> +<td>86893</td> +</tr> +</tbody> +</table> + +</div> +</div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb5"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a>S_df.iloc[:<span class="dv">5</span>, :<span class="dv">5</span>]</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<div> + + +<table class="dataframe table table-sm table-striped small" data-quarto-postprocess="true" data-border="1"> +<thead> +<tr class="header"> +<th data-quarto-table-cell-role="th"></th> +<th data-quarto-table-cell-role="th">nsw-hol-city</th> +<th data-quarto-table-cell-role="th">nsw-hol-noncity</th> +<th data-quarto-table-cell-role="th">vic-hol-city</th> +<th data-quarto-table-cell-role="th">vic-hol-noncity</th> +<th data-quarto-table-cell-role="th">qld-hol-city</th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td data-quarto-table-cell-role="th">total</td> +<td>1.0</td> +<td>1.0</td> +<td>1.0</td> +<td>1.0</td> +<td>1.0</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">hol</td> +<td>1.0</td> +<td>1.0</td> +<td>1.0</td> +<td>1.0</td> +<td>1.0</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">vfr</td> +<td>0.0</td> +<td>0.0</td> +<td>0.0</td> +<td>0.0</td> +<td>0.0</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">bus</td> +<td>0.0</td> +<td>0.0</td> +<td>0.0</td> +<td>0.0</td> +<td>0.0</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">oth</td> +<td>0.0</td> +<td>0.0</td> +<td>0.0</td> +<td>0.0</td> +<td>0.0</td> +</tr> +</tbody> +</table> + +</div> +</div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb6"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a>tags</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<pre><code>{'Country': array(['total'], dtype=object), + 'Country/Purpose': array(['hol', 'vfr', 'bus', 'oth'], dtype=object), + 'Country/Purpose/State': array(['nsw-hol', 'vic-hol', 'qld-hol', 'sa-hol', 'wa-hol', 'tas-hol', + 'nt-hol', 'nsw-vfr', 'vic-vfr', 'qld-vfr', 'sa-vfr', 'wa-vfr', + 'tas-vfr', 'nt-vfr', 'nsw-bus', 'vic-bus', 'qld-bus', 'sa-bus', + 'wa-bus', 'tas-bus', 'nt-bus', 'nsw-oth', 'vic-oth', 'qld-oth', + 'sa-oth', 'wa-oth', 'tas-oth', 'nt-oth'], dtype=object), + 'Country/Purpose/State/CityNonCity': array(['nsw-hol-city', 'nsw-hol-noncity', 'vic-hol-city', + 'vic-hol-noncity', 'qld-hol-city', 'qld-hol-noncity', + 'sa-hol-city', 'sa-hol-noncity', 'wa-hol-city', 'wa-hol-noncity', + 'tas-hol-city', 'tas-hol-noncity', 'nt-hol-city', 'nt-hol-noncity', + 'nsw-vfr-city', 'nsw-vfr-noncity', 'vic-vfr-city', + 'vic-vfr-noncity', 'qld-vfr-city', 'qld-vfr-noncity', + 'sa-vfr-city', 'sa-vfr-noncity', 'wa-vfr-city', 'wa-vfr-noncity', + 'tas-vfr-city', 'tas-vfr-noncity', 'nt-vfr-city', 'nt-vfr-noncity', + 'nsw-bus-city', 'nsw-bus-noncity', 'vic-bus-city', + 'vic-bus-noncity', 'qld-bus-city', 'qld-bus-noncity', + 'sa-bus-city', 'sa-bus-noncity', 'wa-bus-city', 'wa-bus-noncity', + 'tas-bus-city', 'tas-bus-noncity', 'nt-bus-city', 'nt-bus-noncity', + 'nsw-oth-city', 'nsw-oth-noncity', 'vic-oth-city', + 'vic-oth-noncity', 'qld-oth-city', 'qld-oth-noncity', + 'sa-oth-city', 'sa-oth-noncity', 'wa-oth-city', 'wa-oth-noncity', + 'tas-oth-city', 'tas-oth-noncity', 'nt-oth-city', 'nt-oth-noncity'], + dtype=object)}</code></pre> +</div> +</div> +<p>We split the dataframe in train/test splits.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb8"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb8-1"><a href="#cb8-1" aria-hidden="true" tabindex="-1"></a>Y_test_df <span class="op">=</span> Y_df.groupby(<span class="st">'unique_id'</span>).tail(<span class="dv">12</span>)</span> +<span id="cb8-2"><a href="#cb8-2" aria-hidden="true" tabindex="-1"></a>Y_train_df <span class="op">=</span> Y_df.drop(Y_test_df.index)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb9"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb9-1"><a href="#cb9-1" aria-hidden="true" tabindex="-1"></a>Y_test_df <span class="op">=</span> Y_test_df.set_index(<span class="st">'unique_id'</span>)</span> +<span id="cb9-2"><a href="#cb9-2" aria-hidden="true" tabindex="-1"></a>Y_train_df <span class="op">=</span> Y_train_df.set_index(<span class="st">'unique_id'</span>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +</section> +<section id="base-forecasts" class="level2"> +<h2 class="anchored" data-anchor-id="base-forecasts">3. Base forecasts</h2> +<p>The following cell computes the <em>base forecast</em> for each time series using the <code>auto_arima</code> and <code>naive</code> models. Observe that <code>Y_hat_df</code> contains the forecasts but they are not coherent.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb10"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb10-1"><a href="#cb10-1" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> statsforecast.core <span class="im">import</span> StatsForecast</span> +<span id="cb10-2"><a href="#cb10-2" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> statsforecast.models <span class="im">import</span> AutoARIMA, Naive</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb11"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb11-1"><a href="#cb11-1" aria-hidden="true" tabindex="-1"></a>fcst <span class="op">=</span> StatsForecast(</span> +<span id="cb11-2"><a href="#cb11-2" aria-hidden="true" tabindex="-1"></a> df<span class="op">=</span>Y_train_df, </span> +<span id="cb11-3"><a href="#cb11-3" aria-hidden="true" tabindex="-1"></a> models<span class="op">=</span>[AutoARIMA(season_length<span class="op">=</span><span class="dv">12</span>), Naive()], </span> +<span id="cb11-4"><a href="#cb11-4" aria-hidden="true" tabindex="-1"></a> freq<span class="op">=</span><span class="st">'M'</span>, </span> +<span id="cb11-5"><a href="#cb11-5" aria-hidden="true" tabindex="-1"></a> n_jobs<span class="op">=-</span><span class="dv">1</span></span> +<span id="cb11-6"><a href="#cb11-6" aria-hidden="true" tabindex="-1"></a>)</span> +<span id="cb11-7"><a href="#cb11-7" aria-hidden="true" tabindex="-1"></a>Y_hat_df <span class="op">=</span> fcst.forecast(h<span class="op">=</span><span class="dv">12</span>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +</section> +<section id="hierarchical-reconciliation" class="level2"> +<h2 class="anchored" data-anchor-id="hierarchical-reconciliation">4. Hierarchical reconciliation</h2> +<p>The following cell makes the previous forecasts coherent using the <a href="https://Nixtla.github.io/hierarchicalforecast/core.html#hierarchicalreconciliation"><code>HierarchicalReconciliation</code></a> class. The used methods to make the forecasts coherent are:</p> +<ul> +<li><a href="https://Nixtla.github.io/hierarchicalforecast/methods.html#bottomup"><code>BottomUp</code></a>: The reconciliation of the method is a simple addition to the upper levels.</li> +<li><a href="https://Nixtla.github.io/hierarchicalforecast/methods.html#topdown"><code>TopDown</code></a>: The second method constrains the base-level predictions to the top-most aggregate-level serie and then distributes it to the disaggregate series through the use of proportions.</li> +<li><a href="https://Nixtla.github.io/hierarchicalforecast/methods.html#middleout"><code>MiddleOut</code></a>: Anchors the base predictions in a middle level.</li> +</ul> +<div class="cell"> +<div class="sourceCode cell-code" id="cb12"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb12-1"><a href="#cb12-1" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> hierarchicalforecast.core <span class="im">import</span> HierarchicalReconciliation</span> +<span id="cb12-2"><a href="#cb12-2" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> hierarchicalforecast.methods <span class="im">import</span> BottomUp, TopDown, MiddleOut</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb13"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb13-1"><a href="#cb13-1" aria-hidden="true" tabindex="-1"></a>reconcilers <span class="op">=</span> [</span> +<span id="cb13-2"><a href="#cb13-2" aria-hidden="true" tabindex="-1"></a> BottomUp(),</span> +<span id="cb13-3"><a href="#cb13-3" aria-hidden="true" tabindex="-1"></a> TopDown(method<span class="op">=</span><span class="st">'forecast_proportions'</span>),</span> +<span id="cb13-4"><a href="#cb13-4" aria-hidden="true" tabindex="-1"></a> MiddleOut(middle_level<span class="op">=</span><span class="st">'Country/Purpose/State'</span>, </span> +<span id="cb13-5"><a href="#cb13-5" aria-hidden="true" tabindex="-1"></a> top_down_method<span class="op">=</span><span class="st">'forecast_proportions'</span>)</span> +<span id="cb13-6"><a href="#cb13-6" aria-hidden="true" tabindex="-1"></a>]</span> +<span id="cb13-7"><a href="#cb13-7" aria-hidden="true" tabindex="-1"></a>hrec <span class="op">=</span> HierarchicalReconciliation(reconcilers<span class="op">=</span>reconcilers)</span> +<span id="cb13-8"><a href="#cb13-8" aria-hidden="true" tabindex="-1"></a>Y_rec_df <span class="op">=</span> hrec.reconcile(Y_hat_df<span class="op">=</span>Y_hat_df, Y_df<span class="op">=</span>Y_train_df, </span> +<span id="cb13-9"><a href="#cb13-9" aria-hidden="true" tabindex="-1"></a> S<span class="op">=</span>S_df, tags<span class="op">=</span>tags)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +</section> +<section id="evaluation" class="level2"> +<h2 class="anchored" data-anchor-id="evaluation">5. Evaluation</h2> +<p>The <code>HierarchicalForecast</code> package includes the <a href="https://Nixtla.github.io/hierarchicalforecast/evaluation.html#hierarchicalevaluation"><code>HierarchicalEvaluation</code></a> class to evaluate the different hierarchies and also is capable of compute scaled metrics compared to a benchmark model.</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb14"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb14-1"><a href="#cb14-1" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> hierarchicalforecast.evaluation <span class="im">import</span> HierarchicalEvaluation</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +<div class="cell"> +<div class="sourceCode cell-code" id="cb15"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb15-1"><a href="#cb15-1" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> mse(y, y_hat):</span> +<span id="cb15-2"><a href="#cb15-2" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> np.mean((y<span class="op">-</span>y_hat)<span class="op">**</span><span class="dv">2</span>)</span> +<span id="cb15-3"><a href="#cb15-3" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb15-4"><a href="#cb15-4" aria-hidden="true" tabindex="-1"></a>evaluator <span class="op">=</span> HierarchicalEvaluation(evaluators<span class="op">=</span>[mse])</span> +<span id="cb15-5"><a href="#cb15-5" aria-hidden="true" tabindex="-1"></a>evaluation <span class="op">=</span> evaluator.evaluate(</span> +<span id="cb15-6"><a href="#cb15-6" aria-hidden="true" tabindex="-1"></a> Y_hat_df<span class="op">=</span>Y_rec_df, Y_test_df<span class="op">=</span>Y_test_df, </span> +<span id="cb15-7"><a href="#cb15-7" aria-hidden="true" tabindex="-1"></a> tags<span class="op">=</span>tags, benchmark<span class="op">=</span><span class="st">'Naive'</span></span> +<span id="cb15-8"><a href="#cb15-8" aria-hidden="true" tabindex="-1"></a>)</span> +<span id="cb15-9"><a href="#cb15-9" aria-hidden="true" tabindex="-1"></a>evaluation.<span class="bu">filter</span>(like<span class="op">=</span><span class="st">'ARIMA'</span>, axis<span class="op">=</span><span class="dv">1</span>).T</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<div class="cell-output cell-output-display"> +<div> + + +<table class="dataframe table table-sm table-striped small" data-quarto-postprocess="true" data-border="1"> +<thead> +<tr class="header"> +<th data-quarto-table-cell-role="th">level</th> +<th data-quarto-table-cell-role="th">Overall</th> +<th data-quarto-table-cell-role="th">Country</th> +<th data-quarto-table-cell-role="th">Country/Purpose</th> +<th data-quarto-table-cell-role="th">Country/Purpose/State</th> +<th data-quarto-table-cell-role="th">Country/Purpose/State/CityNonCity</th> +</tr> +<tr class="odd"> +<th data-quarto-table-cell-role="th">metric</th> +<th data-quarto-table-cell-role="th">mse-scaled</th> +<th data-quarto-table-cell-role="th">mse-scaled</th> +<th data-quarto-table-cell-role="th">mse-scaled</th> +<th data-quarto-table-cell-role="th">mse-scaled</th> +<th data-quarto-table-cell-role="th">mse-scaled</th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td data-quarto-table-cell-role="th">AutoARIMA</td> +<td>0.958324</td> +<td>1.051911</td> +<td>0.903933</td> +<td>0.909364</td> +<td>0.845968</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">AutoARIMA/BottomUp</td> +<td>0.911524</td> +<td>0.984391</td> +<td>0.86538</td> +<td>0.865384</td> +<td>0.845968</td> +</tr> +<tr class="odd"> +<td data-quarto-table-cell-role="th">AutoARIMA/TopDown_method-forecast_proportions</td> +<td>0.973036</td> +<td>1.051911</td> +<td>0.88765</td> +<td>0.973843</td> +<td>0.949449</td> +</tr> +<tr class="even"> +<td data-quarto-table-cell-role="th">AutoARIMA/MiddleOut_middle_level-Country/Purpose/State_top_down_method-forecast_proportions</td> +<td>0.896147</td> +<td>0.950773</td> +<td>0.830191</td> +<td>0.909364</td> +<td>0.885306</td> +</tr> +</tbody> +</table> + +</div> +</div> +</div> +<section id="references" class="level3"> +<h3 class="anchored" data-anchor-id="references">References</h3> +<ul> +<li><a href="http://www.jstor.org/stable/1815532">Orcutt, G.H., Watts, H.W., & Edwards, J.B.(1968). Data aggregation and information loss. The American Economic Review, 58 , 773{787)</a>.</li> +<li><a href="https://onlinelibrary.wiley.com/doi/abs/10.1002/for.3980090304">Disaggregation methods to expedite product line forecasting. Journal of Forecasting, 9 , 233ā254. doi:10.1002/for.3980090304</a>.<br></li> +<li><a href="https://doi.org/10.1016/S0305-0548(99)00017-9">An investigation of aggregate variable time series forecast strategies with specific subaggregate time series statistical correlation. Computers and Operations Research, 26 , 1133ā1149. doi:10.1016/S0305-0548(99)00017-9</a>.</li> +<li><a href="https://otexts.com/fpp3/hierarchical.html">Hyndman, R.J., & Athanasopoulos, G. (2021). āForecasting: principles and practice, 3rd edition: Chapter 11: Forecasting hierarchical and grouped series.ā. OTexts: Melbourne, Australia. OTexts.com/fpp3 Accessed on July 2022.</a></li> +</ul> + + +</section> +</section> + +<p>If you find the code useful, please ā us on <a href="https://github.com/nixtla/hierarchicalforecast">Github</a></p></main> <!-- /main --> +<script id="quarto-html-after-body" type="application/javascript"> +window.document.addEventListener("DOMContentLoaded", function (event) { + const toggleBodyColorMode = (bsSheetEl) => { + const mode = bsSheetEl.getAttribute("data-mode"); + const bodyEl = window.document.querySelector("body"); + if (mode === "dark") { + bodyEl.classList.add("quarto-dark"); + bodyEl.classList.remove("quarto-light"); + } else { + bodyEl.classList.add("quarto-light"); + bodyEl.classList.remove("quarto-dark"); + } + } + const toggleBodyColorPrimary = () => { + const bsSheetEl = window.document.querySelector("link#quarto-bootstrap"); + if (bsSheetEl) { + toggleBodyColorMode(bsSheetEl); + } + } + toggleBodyColorPrimary(); + const icon = "ī§"; + const anchorJS = new window.AnchorJS(); + anchorJS.options = { + placement: 'right', + icon: icon + }; + anchorJS.add('.anchored'); + const isCodeAnnotation = (el) => { + for (const clz of el.classList) { + if (clz.startsWith('code-annotation-')) { + return true; + } + } + return false; + } + const clipboard = new window.ClipboardJS('.code-copy-button', { + text: function(trigger) { + const codeEl = trigger.previousElementSibling.cloneNode(true); + for (const childEl of codeEl.children) { + if (isCodeAnnotation(childEl)) { + childEl.remove(); + } + } + return codeEl.innerText; + } + }); + clipboard.on('success', function(e) { + // button target + const button = e.trigger; + // don't keep focus + button.blur(); + // flash "checked" + button.classList.add('code-copy-button-checked'); + var currentTitle = button.getAttribute("title"); + button.setAttribute("title", "Copied!"); + let tooltip; + if (window.bootstrap) { + button.setAttribute("data-bs-toggle", "tooltip"); + button.setAttribute("data-bs-placement", "left"); + button.setAttribute("data-bs-title", "Copied!"); + tooltip = new bootstrap.Tooltip(button, + { trigger: "manual", + customClass: "code-copy-button-tooltip", + offset: [0, -8]}); + tooltip.show(); + } + setTimeout(function() { + if (tooltip) { + tooltip.hide(); + button.removeAttribute("data-bs-title"); + button.removeAttribute("data-bs-toggle"); + button.removeAttribute("data-bs-placement"); + } + button.setAttribute("title", currentTitle); + button.classList.remove('code-copy-button-checked'); + }, 1000); + // clear code selection + e.clearSelection(); + }); + function tippyHover(el, contentFn) { + const config = { + allowHTML: true, + content: contentFn, + maxWidth: 500, + delay: 100, + arrow: false, + appendTo: function(el) { + return el.parentElement; + }, + interactive: true, + interactiveBorder: 10, + theme: 'quarto', + placement: 'bottom-start' + }; + window.tippy(el, config); + } + const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]'); + for (var i=0; i<noterefs.length; i++) { + const ref = noterefs[i]; + tippyHover(ref, function() { + // use id or data attribute instead here + let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href'); + try { href = new URL(href).hash; } catch {} + const id = href.replace(/^#\/?/, ""); + const note = window.document.getElementById(id); + return note.innerHTML; + }); + } + let selectedAnnoteEl; + const selectorForAnnotation = ( cell, annotation) => { + let cellAttr = 'data-code-cell="' + cell + '"'; + let lineAttr = 'data-code-annotation="' + annotation + '"'; + const selector = 'span[' + cellAttr + '][' + lineAttr + ']'; + return selector; + } + const selectCodeLines = (annoteEl) => { + const doc = window.document; + const targetCell = annoteEl.getAttribute("data-target-cell"); + const targetAnnotation = annoteEl.getAttribute("data-target-annotation"); + const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation)); + const lines = annoteSpan.getAttribute("data-code-lines").split(","); + const lineIds = lines.map((line) => { + return targetCell + "-" + line; + }) + let top = null; + let height = null; + let parent = null; + if (lineIds.length > 0) { + //compute the position of the single el (top and bottom and make a div) + const el = window.document.getElementById(lineIds[0]); + top = el.offsetTop; + height = el.offsetHeight; + parent = el.parentElement.parentElement; + if (lineIds.length > 1) { + const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]); + const bottom = lastEl.offsetTop + lastEl.offsetHeight; + height = bottom - top; + } + if (top !== null && height !== null && parent !== null) { + // cook up a div (if necessary) and position it + let div = window.document.getElementById("code-annotation-line-highlight"); + if (div === null) { + div = window.document.createElement("div"); + div.setAttribute("id", "code-annotation-line-highlight"); + div.style.position = 'absolute'; + parent.appendChild(div); + } + div.style.top = top - 2 + "px"; + div.style.height = height + 4 + "px"; + let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter"); + if (gutterDiv === null) { + gutterDiv = window.document.createElement("div"); + gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter"); + gutterDiv.style.position = 'absolute'; + const codeCell = window.document.getElementById(targetCell); + const gutter = codeCell.querySelector('.code-annotation-gutter'); + gutter.appendChild(gutterDiv); + } + gutterDiv.style.top = top - 2 + "px"; + gutterDiv.style.height = height + 4 + "px"; + } + selectedAnnoteEl = annoteEl; + } + }; + const unselectCodeLines = () => { + const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"]; + elementsIds.forEach((elId) => { + const div = window.document.getElementById(elId); + if (div) { + div.remove(); + } + }); + selectedAnnoteEl = undefined; + }; + // Attach click handler to the DT + const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); + for (const annoteDlNode of annoteDls) { + annoteDlNode.addEventListener('click', (event) => { + const clickedEl = event.target; + if (clickedEl !== selectedAnnoteEl) { + unselectCodeLines(); + const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active'); + if (activeEl) { + activeEl.classList.remove('code-annotation-active'); + } + selectCodeLines(clickedEl); + clickedEl.classList.add('code-annotation-active'); + } else { + // Unselect the line + unselectCodeLines(); + clickedEl.classList.remove('code-annotation-active'); + } + }); + } + const findCites = (el) => { + const parentEl = el.parentElement; + if (parentEl) { + const cites = parentEl.dataset.cites; + if (cites) { + return { + el, + cites: cites.split(' ') + }; + } else { + return findCites(el.parentElement) + } + } else { + return undefined; + } + }; + var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]'); + for (var i=0; i<bibliorefs.length; i++) { + const ref = bibliorefs[i]; + const citeInfo = findCites(ref); + if (citeInfo) { + tippyHover(citeInfo.el, function() { + var popup = window.document.createElement('div'); + citeInfo.cites.forEach(function(cite) { + var citeDiv = window.document.createElement('div'); + citeDiv.classList.add('hanging-indent'); + citeDiv.classList.add('csl-entry'); + var biblioDiv = window.document.getElementById('ref-' + cite); + if (biblioDiv) { + citeDiv.innerHTML = biblioDiv.innerHTML; + } + popup.appendChild(citeDiv); + }); + return popup.innerHTML; + }); + } + } +}); +</script> +</div> <!-- /content --> + + + +</body></html> \ No newline at end of file diff --git a/favicon_png.png b/favicon_png.png new file mode 100644 index 00000000..7c7684de Binary files /dev/null and b/favicon_png.png differ diff --git a/index.html b/index.html new file mode 100644 index 00000000..407b1d6e --- /dev/null +++ b/index.html @@ -0,0 +1,819 @@ +<!DOCTYPE html> +<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head> + +<meta charset="utf-8"> +<meta name="generator" content="quarto-1.3.450"> + +<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes"> + + +<title>hierarchicalforecast - Hierarchical Forecast š</title> +<style> +code{white-space: pre-wrap;} +span.smallcaps{font-variant: small-caps;} +div.columns{display: flex; gap: min(4vw, 1.5em);} +div.column{flex: auto; overflow-x: auto;} +div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;} +ul.task-list{list-style: none;} +ul.task-list li input[type="checkbox"] { + width: 0.8em; + margin: 0 0.8em 0.2em -1em; /* quarto-specific, see https://github.com/quarto-dev/quarto-cli/issues/4556 */ + vertical-align: middle; +} +/* CSS for syntax highlighting */ +pre > code.sourceCode { white-space: pre; position: relative; } +pre > code.sourceCode > span { display: inline-block; line-height: 1.25; } +pre > code.sourceCode > span:empty { height: 1.2em; } +.sourceCode { overflow: visible; } +code.sourceCode > span { color: inherit; text-decoration: inherit; } +div.sourceCode { margin: 1em 0; } +pre.sourceCode { margin: 0; } +@media screen { +div.sourceCode { overflow: auto; } +} +@media print { +pre > code.sourceCode { white-space: pre-wrap; } +pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; } +} +pre.numberSource code + { counter-reset: source-line 0; } +pre.numberSource code > span + { position: relative; left: -4em; counter-increment: source-line; } +pre.numberSource code > span > a:first-child::before + { content: counter(source-line); + position: relative; left: -1em; text-align: right; vertical-align: baseline; + border: none; display: inline-block; + -webkit-touch-callout: none; -webkit-user-select: none; + -khtml-user-select: none; -moz-user-select: none; + -ms-user-select: none; user-select: none; + padding: 0 4px; width: 4em; + } +pre.numberSource { margin-left: 3em; padding-left: 4px; } +div.sourceCode + { } +@media screen { +pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; } +} +</style> + + +<script src="site_libs/quarto-nav/quarto-nav.js"></script> +<script src="site_libs/quarto-nav/headroom.min.js"></script> +<script src="site_libs/clipboard/clipboard.min.js"></script> +<script src="site_libs/quarto-search/autocomplete.umd.js"></script> +<script src="site_libs/quarto-search/fuse.min.js"></script> +<script src="site_libs/quarto-search/quarto-search.js"></script> +<meta name="quarto:offset" content="./"> +<link href="./favicon_png.png" rel="icon" type="image/png"> +<script src="site_libs/quarto-html/quarto.js"></script> +<script src="site_libs/quarto-html/popper.min.js"></script> +<script src="site_libs/quarto-html/tippy.umd.min.js"></script> +<script src="site_libs/quarto-html/anchor.min.js"></script> +<link href="site_libs/quarto-html/tippy.css" rel="stylesheet"> +<link href="site_libs/quarto-html/quarto-syntax-highlighting.css" rel="stylesheet" id="quarto-text-highlighting-styles"> +<script src="site_libs/bootstrap/bootstrap.min.js"></script> +<link href="site_libs/bootstrap/bootstrap-icons.css" rel="stylesheet"> +<link href="site_libs/bootstrap/bootstrap.min.css" rel="stylesheet" id="quarto-bootstrap" data-mode="light"> +<script id="quarto-search-options" type="application/json">{ + "location": "navbar", + "copy-button": false, + "collapse-after": 3, + "panel-placement": "end", + "type": "overlay", + "limit": 20, + "language": { + "search-no-results-text": "No results", + "search-matching-documents-text": "matching documents", + "search-copy-link-title": "Copy link to search", + "search-hide-matches-text": "Hide additional matches", + "search-more-match-text": "more match in this document", + "search-more-matches-text": "more matches in this document", + "search-clear-button-title": "Clear", + "search-detached-cancel-button-title": "Cancel", + "search-submit-button-title": "Submit", + "search-label": "Search" + } +}</script> +<script async="" src="https://www.googletagmanager.com/gtag/js?id=G-NXJNCVR18L"></script> + +<script type="text/javascript"> + +window.dataLayer = window.dataLayer || []; +function gtag(){dataLayer.push(arguments);} +gtag('js', new Date()); +gtag('config', 'G-NXJNCVR18L', { 'anonymize_ip': true}); +</script> + + +<link rel="stylesheet" href="styles.css"> +<meta property="og:title" content="hierarchicalforecast - Hierarchical Forecast š"> +<meta property="og:description" content=""> +<meta property="og:image" content="https://img.shields.io/badge/Slack-4A154B?&logo=slack&logoColor=white.png"> +<meta property="og:site-name" content="hierarchicalforecast"> +<meta name="twitter:title" content="hierarchicalforecast - Hierarchical Forecast š"> +<meta name="twitter:description" content=""> +<meta name="twitter:image" content="https://img.shields.io/badge/Slack-4A154B?&logo=slack&logoColor=white.png"> +<meta name="twitter:card" content="summary_large_image"> +</head> + +<body class="nav-sidebar floating nav-fixed"> + +<div id="quarto-search-results"></div> + <header id="quarto-header" class="headroom fixed-top"> + <nav class="navbar navbar-expand-lg navbar-dark "> + <div class="navbar-container container-fluid"> + <div class="navbar-brand-container"> + <a class="navbar-brand" href="./index.html"> + <span class="navbar-title">hierarchicalforecast</span> + </a> + </div> + <div id="quarto-search" class="" title="Search"></div> + <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + <span class="navbar-toggler-icon"></span> +</button> + <div class="collapse navbar-collapse" id="navbarCollapse"> + <ul class="navbar-nav navbar-nav-scroll me-auto"> + <li class="nav-item"> + <a class="nav-link active" href="./examples/tourismsmall.html" rel="" target="" aria-current="page"> + <span class="menu-text">Get Started</span></a> + </li> + <li class="nav-item dropdown "> + <a class="nav-link dropdown-toggle" href="#" id="nav-menu-nixtlaverse" role="button" data-bs-toggle="dropdown" aria-expanded="false" rel="" target=""> + <span class="menu-text">NixtlaVerse</span> + </a> + <ul class="dropdown-menu" aria-labelledby="nav-menu-nixtlaverse"> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/mlforecast" rel="" target=""> + <span class="dropdown-text">MLForecast š¤</span></a> + </li> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/neuralforecast" rel="" target=""> + <span class="dropdown-text">NeuralForecast š§ </span></a> + </li> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/statsforecast" rel="" target=""> + <span class="dropdown-text">StatsForecast ā”ļø</span></a> + </li> + </ul> + </li> + <li class="nav-item dropdown "> + <a class="nav-link dropdown-toggle" href="#" id="nav-menu-help" role="button" data-bs-toggle="dropdown" aria-expanded="false" rel="" target=""> + <span class="menu-text">Help</span> + </a> + <ul class="dropdown-menu" aria-labelledby="nav-menu-help"> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/hierarchicalforecast/issues/new/choose" rel="" target=""><i class="bi bi-bug" role="img"> +</i> + <span class="dropdown-text">Report an Issue</span></a> + </li> + <li> + <a class="dropdown-item" href="https://join.slack.com/t/nixtlacommunity/shared_invite/zt-1kd5m5db7-7OOfy0xVNf1PcvCiAPWvPw" rel="" target=""><i class="bi bi-chat-right-text" role="img"> +</i> + <span class="dropdown-text">Join our Slack</span></a> + </li> + </ul> + </li> +</ul> + <ul class="navbar-nav navbar-nav-scroll ms-auto"> + <li class="nav-item compact"> + <a class="nav-link" href="https://github.com/nixtla/hierarchicalforecast" rel="" target=""><i class="bi bi-github" role="img"> +</i> + <span class="menu-text"></span></a> + </li> + <li class="nav-item compact"> + <a class="nav-link" href="https://twitter.com/nixtlainc" rel="" target=""><i class="bi bi-twitter" role="img" aria-label="Nixtla Twitter"> +</i> + <span class="menu-text"></span></a> + </li> +</ul> + <div class="quarto-navbar-tools"> +</div> + </div> <!-- /navcollapse --> + </div> <!-- /container-fluid --> + </nav> + <nav class="quarto-secondary-nav"> + <div class="container-fluid d-flex"> + <button type="button" class="quarto-btn-toggle btn" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + <i class="bi bi-layout-text-sidebar-reverse"></i> + </button> + <nav class="quarto-page-breadcrumbs" aria-label="breadcrumb"><ol class="breadcrumb"><li class="breadcrumb-item"><a href="./index.html">Hierarchical Forecast š</a></li></ol></nav> + <a class="flex-grow-1" role="button" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + </a> + </div> + </nav> +</header> +<!-- content --> +<div id="quarto-content" class="quarto-container page-columns page-rows-contents page-layout-article page-navbar"> +<!-- sidebar --> + <nav id="quarto-sidebar" class="sidebar collapse collapse-horizontal sidebar-navigation floating overflow-auto"> + <div class="sidebar-menu-container"> + <ul class="list-unstyled mt-1"> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./index.html" class="sidebar-item-text sidebar-link active"> + <span class="menu-text">Hierarchical Forecast š</span></a> + </div> +</li> + <li class="px-0"><hr class="sidebar-divider hi "></li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-1" aria-expanded="false"> + <span class="menu-text">Getting Started</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-1" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-1" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/installation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Install</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/tourismsmall.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Reconciliation Quick Start</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/introduction.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Introduction</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-2" aria-expanded="false"> + <span class="menu-text">Tutorials</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-2" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-2" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-3" aria-expanded="false"> + <span class="menu-text">Point Reconciliation</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-3" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-3" class="collapse list-unstyled sidebar-section depth2 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/australiandomestictourism.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Geographical Aggregation (Tourism)</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/australianprisonpopulation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Geographical Aggregation (Prison Population)</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/nonnegativereconciliation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Non-Negative MinTrace</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-4" aria-expanded="false"> + <span class="menu-text">Probabilistic Reconciliation</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-4" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-4" class="collapse list-unstyled sidebar-section depth2 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/australiandomestictourism-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Normality</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/australiandomestictourism-bootstraped-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Bootstrap</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/australiandomestictourism-permbu-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">PERMBU</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/tourismlarge-evaluation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Probabilistic Forecast Evaluation</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-5" aria-expanded="false"> + <span class="menu-text">ML Forecast Reconciliation</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-5" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-5" class="collapse list-unstyled sidebar-section depth2 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/hierarchicalforecast-gluonts.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">GluonTS</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/mlframeworksexample.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Neural/MLForecast</span></a> + </div> +</li> + </ul> + </li> + </ul> + </li> + <li class="sidebar-item"> + <span class="menu-text">Methods</span> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-6" aria-expanded="false"> + <span class="menu-text">API Reference</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-6" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-6" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./core.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Core </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./methods.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Reconciliation Methods </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./probabilistic_methods.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Probabilistic Methods </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./evaluation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Hierarchical Evaluation</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./utils.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Aggregation/Visualization Utils</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-7" aria-expanded="false"> + <span class="menu-text">Community</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-7" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-7" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item"> + <span class="menu-text">Contributing</span> + </li> + </ul> + </li> + </ul> + </div> +</nav> +<div id="quarto-sidebar-glass" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass"></div> +<!-- margin-sidebar --> + <div id="quarto-margin-sidebar" class="sidebar margin-sidebar"> + <nav id="TOC" role="doc-toc" class="toc-active"> + <h2 id="toc-title">On this page</h2> + + <ul> + <li><a href="#features" id="toc-features" class="nav-link active" data-scroll-target="#features">š Features</a></li> + <li><a href="#why" id="toc-why" class="nav-link" data-scroll-target="#why">š Why?</a></li> + <li><a href="#installation" id="toc-installation" class="nav-link" data-scroll-target="#installation">š» Installation</a> + <ul class="collapse"> + <li><a href="#pypi" id="toc-pypi" class="nav-link" data-scroll-target="#pypi">PyPI</a></li> + <li><a href="#conda" id="toc-conda" class="nav-link" data-scroll-target="#conda">Conda</a></li> + <li><a href="#dev-mode" id="toc-dev-mode" class="nav-link" data-scroll-target="#dev-mode">Dev Mode</a></li> + </ul></li> + <li><a href="#how-to-use" id="toc-how-to-use" class="nav-link" data-scroll-target="#how-to-use">š§¬ How to use</a> + <ul class="collapse"> + <li><a href="#evaluation" id="toc-evaluation" class="nav-link" data-scroll-target="#evaluation">Evaluation</a></li> + </ul></li> + <li><a href="#how-to-cite" id="toc-how-to-cite" class="nav-link" data-scroll-target="#how-to-cite">How to cite</a></li> + </ul> +<div class="toc-actions"><div><i class="bi bi-github"></i></div><div class="action-links"><p><a href="https://github.com/Nixtla/hierarchicalforecast/issues/new" class="toc-action">Report an issue</a></p></div></div></nav> + </div> +<!-- main --> +<main class="content" id="quarto-document-content"> + +<header id="title-block-header" class="quarto-title-block default"> +<div class="quarto-title"> +<h1 class="title">Hierarchical Forecast š</h1> +</div> + + + +<div class="quarto-title-meta"> + + + + + </div> + + +</header> + +<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! --> +<p>Large collections of time series organized into structures at different aggregation levels often require their forecasts to follow their aggregation constraints, which poses the challenge of creating novel algorithms capable of coherent forecasts.</p> +<p><strong>HierarchicalForecast</strong> offers a collection of reconciliation methods, including <a href="https://Nixtla.github.io/hierarchicalforecast/methods.html#bottomup"><code>BottomUp</code></a>, <a href="https://Nixtla.github.io/hierarchicalforecast/methods.html#topdown"><code>TopDown</code></a>, <a href="https://Nixtla.github.io/hierarchicalforecast/methods.html#middleout"><code>MiddleOut</code></a>, <a href="https://Nixtla.github.io/hierarchicalforecast/methods.html#mintrace"><code>MinTrace</code></a> and <a href="https://Nixtla.github.io/hierarchicalforecast/methods.html#erm"><code>ERM</code></a>. And Probabilistic coherent predictions including <a href="https://Nixtla.github.io/hierarchicalforecast/probabilistic_methods.html#normality"><code>Normality</code></a>, <a href="https://Nixtla.github.io/hierarchicalforecast/probabilistic_methods.html#bootstrap"><code>Bootstrap</code></a>, and <a href="https://Nixtla.github.io/hierarchicalforecast/probabilistic_methods.html#permbu"><code>PERMBU</code></a>.</p> +<section id="features" class="level2"> +<h2 class="anchored" data-anchor-id="features">š Features</h2> +<ul> +<li>Classic reconciliation methods: +<ul> +<li><code>BottomUp</code>: Simple addition to the upper levels.</li> +<li><code>TopDown</code>: Distributes the top levels forecasts trough the hierarchies.</li> +</ul></li> +<li>Alternative reconciliation methods: +<ul> +<li><code>MiddleOut</code>: It anchors the base predictions in a middle level. The levels above the base predictions use the bottom-up approach, while the levels below use a top-down.</li> +<li><code>MinTrace</code>: Minimizes the total forecast variance of the space of coherent forecasts, with the Minimum Trace reconciliation.</li> +<li><code>ERM</code>: Optimizes the reconciliation matrix minimizing an L1 regularized objective.</li> +</ul></li> +<li>Probabilistic coherent methods: +<ul> +<li><code>Normality</code>: Uses MinTrace variance-covariance closed form matrix under a normality assumption.</li> +<li><code>Bootstrap</code>: Generates distribution of hierarchically reconciled predictions using Gamakumaraās bootstrap approach.</li> +<li><code>PERMBU</code>: Reconciles independent sample predictions by reinjecting multivariate dependence with estimated rank permutation copulas, and performing a Bottom-Up aggregation.</li> +</ul></li> +</ul> +<p>Missing something? Please open an issue here or write us in <a href="https://join.slack.com/t/nixtlaworkspace/shared_invite/zt-135dssye9-fWTzMpv2WBthq8NK0Yvu6A"><img src="https://img.shields.io/badge/Slack-4A154B?&logo=slack&logoColor=white.png" class="img-fluid" alt="Slack"></a></p> +</section> +<section id="why" class="level2"> +<h2 class="anchored" data-anchor-id="why">š Why?</h2> +<p><strong>Short</strong>: We want to contribute to the ML field by providing reliable baselines and benchmarks for hierarchical forecasting task in industry and academia. Hereās the complete <a href="https://arxiv.org/abs/2207.03517">paper</a>.</p> +<p><strong>Verbose</strong>: <code>HierarchicalForecast</code> integrates publicly available processed datasets, evaluation metrics, and a curated set of statistical baselines. In this library we provide usage examples and references to extensive experiments where we showcase the baselineās use and evaluate the accuracy of their predictions. With this work, we hope to contribute to Machine Learning forecasting by bridging the gap to statistical and econometric modeling, as well as providing tools for the development of novel hierarchical forecasting algorithms rooted in a thorough comparison of these well-established models. We intend to continue maintaining and increasing the repository, promoting collaboration across the forecasting community.</p> +</section> +<section id="installation" class="level2"> +<h2 class="anchored" data-anchor-id="installation">š» Installation</h2> +<section id="pypi" class="level3"> +<h3 class="anchored" data-anchor-id="pypi">PyPI</h3> +<p>You can install the <em>released version</em> of <code>HierarchicalForecast</code> from the <a href="https://pypi.org">Python package index</a> with:</p> +<div class="sourceCode" id="cb1"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb1-1"><a href="#cb1-1" aria-hidden="true" tabindex="-1"></a>pip install hierarchicalforecast</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<p>(Installing inside a python virtualenvironment or a conda environment is recommended.)</p> +</section> +<section id="conda" class="level3"> +<h3 class="anchored" data-anchor-id="conda">Conda</h3> +<p>Also you can install the <em>released version</em> of <code>HierarchicalForecast</code> from <a href="https://anaconda.org">conda</a> with:</p> +<div class="sourceCode" id="cb2"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb2-1"><a href="#cb2-1" aria-hidden="true" tabindex="-1"></a>conda install <span class="op">-</span>c conda<span class="op">-</span>forge hierarchicalforecast</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<p>(Installing inside a python virtualenvironment or a conda environment is recommended.)</p> +</section> +<section id="dev-mode" class="level3"> +<h3 class="anchored" data-anchor-id="dev-mode">Dev Mode</h3> +<p>If you want to make some modifications to the code and see the effects in real time (without reinstalling), follow the steps below:</p> +<div class="sourceCode" id="cb3"><pre class="sourceCode bash code-with-copy"><code class="sourceCode bash"><span id="cb3-1"><a href="#cb3-1" aria-hidden="true" tabindex="-1"></a><span class="fu">git</span> clone https://github.com/Nixtla/hierarchicalforecast.git</span> +<span id="cb3-2"><a href="#cb3-2" aria-hidden="true" tabindex="-1"></a><span class="bu">cd</span> hierarchicalforecast</span> +<span id="cb3-3"><a href="#cb3-3" aria-hidden="true" tabindex="-1"></a><span class="ex">pip</span> install <span class="at">-e</span> .</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</section> +</section> +<section id="how-to-use" class="level2"> +<h2 class="anchored" data-anchor-id="how-to-use">š§¬ How to use</h2> +<p>The following example needs <code>statsforecast</code> and <code>datasetsforecast</code> as additional packages. If not installed, install it via your preferred method, e.g. <code>pip install statsforecast datasetsforecast</code>. The <code>datasetsforecast</code> library allows us to download hierarhical datasets and we will use <code>statsforecast</code> to compute base forecasts to be reconciled.</p> +<p>You can open this example in Colab <a href="https://colab.research.google.com/github/nixtla/hierarchicalforecast/blob/main/nbs/examples/TourismSmall.ipynb"><img src="https://colab.research.google.com/assets/colab-badge.svg" class="img-fluid" alt="Open In Colab"></a></p> +<div class="sourceCode" id="cb4"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb4-1"><a href="#cb4-1" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> numpy <span class="im">as</span> np</span> +<span id="cb4-2"><a href="#cb4-2" aria-hidden="true" tabindex="-1"></a><span class="im">import</span> pandas <span class="im">as</span> pd</span> +<span id="cb4-3"><a href="#cb4-3" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb4-4"><a href="#cb4-4" aria-hidden="true" tabindex="-1"></a><span class="co">#obtain hierarchical dataset</span></span> +<span id="cb4-5"><a href="#cb4-5" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> datasetsforecast.hierarchical <span class="im">import</span> HierarchicalData</span> +<span id="cb4-6"><a href="#cb4-6" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb4-7"><a href="#cb4-7" aria-hidden="true" tabindex="-1"></a><span class="co"># compute base forecast no coherent</span></span> +<span id="cb4-8"><a href="#cb4-8" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> statsforecast.core <span class="im">import</span> StatsForecast</span> +<span id="cb4-9"><a href="#cb4-9" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> statsforecast.models <span class="im">import</span> AutoARIMA, Naive</span> +<span id="cb4-10"><a href="#cb4-10" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb4-11"><a href="#cb4-11" aria-hidden="true" tabindex="-1"></a><span class="co">#obtain hierarchical reconciliation methods and evaluation</span></span> +<span id="cb4-12"><a href="#cb4-12" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> hierarchicalforecast.core <span class="im">import</span> HierarchicalReconciliation</span> +<span id="cb4-13"><a href="#cb4-13" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> hierarchicalforecast.evaluation <span class="im">import</span> HierarchicalEvaluation</span> +<span id="cb4-14"><a href="#cb4-14" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> hierarchicalforecast.methods <span class="im">import</span> BottomUp, TopDown, MiddleOut</span> +<span id="cb4-15"><a href="#cb4-15" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb4-16"><a href="#cb4-16" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb4-17"><a href="#cb4-17" aria-hidden="true" tabindex="-1"></a><span class="co"># Load TourismSmall dataset</span></span> +<span id="cb4-18"><a href="#cb4-18" aria-hidden="true" tabindex="-1"></a>Y_df, S, tags <span class="op">=</span> HierarchicalData.load(<span class="st">'./data'</span>, <span class="st">'TourismSmall'</span>)</span> +<span id="cb4-19"><a href="#cb4-19" aria-hidden="true" tabindex="-1"></a>Y_df[<span class="st">'ds'</span>] <span class="op">=</span> pd.to_datetime(Y_df[<span class="st">'ds'</span>])</span> +<span id="cb4-20"><a href="#cb4-20" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb4-21"><a href="#cb4-21" aria-hidden="true" tabindex="-1"></a><span class="co">#split train/test sets</span></span> +<span id="cb4-22"><a href="#cb4-22" aria-hidden="true" tabindex="-1"></a>Y_test_df <span class="op">=</span> Y_df.groupby(<span class="st">'unique_id'</span>).tail(<span class="dv">12</span>)</span> +<span id="cb4-23"><a href="#cb4-23" aria-hidden="true" tabindex="-1"></a>Y_train_df <span class="op">=</span> Y_df.drop(Y_test_df.index)</span> +<span id="cb4-24"><a href="#cb4-24" aria-hidden="true" tabindex="-1"></a>Y_test_df <span class="op">=</span> Y_test_df.set_index(<span class="st">'unique_id'</span>)</span> +<span id="cb4-25"><a href="#cb4-25" aria-hidden="true" tabindex="-1"></a>Y_train_df <span class="op">=</span> Y_train_df.set_index(<span class="st">'unique_id'</span>)</span> +<span id="cb4-26"><a href="#cb4-26" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb4-27"><a href="#cb4-27" aria-hidden="true" tabindex="-1"></a><span class="co"># Compute base auto-ARIMA predictions</span></span> +<span id="cb4-28"><a href="#cb4-28" aria-hidden="true" tabindex="-1"></a>fcst <span class="op">=</span> StatsForecast(df<span class="op">=</span>Y_train_df, </span> +<span id="cb4-29"><a href="#cb4-29" aria-hidden="true" tabindex="-1"></a> models<span class="op">=</span>[AutoARIMA(season_length<span class="op">=</span><span class="dv">12</span>), Naive()], </span> +<span id="cb4-30"><a href="#cb4-30" aria-hidden="true" tabindex="-1"></a> freq<span class="op">=</span><span class="st">'M'</span>, n_jobs<span class="op">=-</span><span class="dv">1</span>)</span> +<span id="cb4-31"><a href="#cb4-31" aria-hidden="true" tabindex="-1"></a>Y_hat_df <span class="op">=</span> fcst.forecast(h<span class="op">=</span><span class="dv">12</span>)</span> +<span id="cb4-32"><a href="#cb4-32" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb4-33"><a href="#cb4-33" aria-hidden="true" tabindex="-1"></a><span class="co"># Reconcile the base predictions</span></span> +<span id="cb4-34"><a href="#cb4-34" aria-hidden="true" tabindex="-1"></a>reconcilers <span class="op">=</span> [</span> +<span id="cb4-35"><a href="#cb4-35" aria-hidden="true" tabindex="-1"></a> BottomUp(),</span> +<span id="cb4-36"><a href="#cb4-36" aria-hidden="true" tabindex="-1"></a> TopDown(method<span class="op">=</span><span class="st">'forecast_proportions'</span>),</span> +<span id="cb4-37"><a href="#cb4-37" aria-hidden="true" tabindex="-1"></a> MiddleOut(middle_level<span class="op">=</span><span class="st">'Country/Purpose/State'</span>,</span> +<span id="cb4-38"><a href="#cb4-38" aria-hidden="true" tabindex="-1"></a> top_down_method<span class="op">=</span><span class="st">'forecast_proportions'</span>)</span> +<span id="cb4-39"><a href="#cb4-39" aria-hidden="true" tabindex="-1"></a>]</span> +<span id="cb4-40"><a href="#cb4-40" aria-hidden="true" tabindex="-1"></a>hrec <span class="op">=</span> HierarchicalReconciliation(reconcilers<span class="op">=</span>reconcilers)</span> +<span id="cb4-41"><a href="#cb4-41" aria-hidden="true" tabindex="-1"></a>Y_rec_df <span class="op">=</span> hrec.reconcile(Y_hat_df<span class="op">=</span>Y_hat_df, Y_df<span class="op">=</span>Y_train_df, </span> +<span id="cb4-42"><a href="#cb4-42" aria-hidden="true" tabindex="-1"></a> S<span class="op">=</span>S, tags<span class="op">=</span>tags)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +<section id="evaluation" class="level3"> +<h3 class="anchored" data-anchor-id="evaluation">Evaluation</h3> +<div class="sourceCode" id="cb5"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb5-1"><a href="#cb5-1" aria-hidden="true" tabindex="-1"></a><span class="kw">def</span> mse(y, y_hat):</span> +<span id="cb5-2"><a href="#cb5-2" aria-hidden="true" tabindex="-1"></a> <span class="cf">return</span> np.mean((y<span class="op">-</span>y_hat)<span class="op">**</span><span class="dv">2</span>)</span> +<span id="cb5-3"><a href="#cb5-3" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb5-4"><a href="#cb5-4" aria-hidden="true" tabindex="-1"></a>evaluator <span class="op">=</span> HierarchicalEvaluation(evaluators<span class="op">=</span>[mse])</span> +<span id="cb5-5"><a href="#cb5-5" aria-hidden="true" tabindex="-1"></a>evaluator.evaluate(Y_h<span class="op">=</span>Y_rec_df, Y_test<span class="op">=</span>Y_df_test, </span> +<span id="cb5-6"><a href="#cb5-6" aria-hidden="true" tabindex="-1"></a> tags<span class="op">=</span>tags, benchmark<span class="op">=</span><span class="st">'Naive'</span>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</section> +</section> +<section id="how-to-cite" class="level2"> +<h2 class="anchored" data-anchor-id="how-to-cite">How to cite</h2> +<p>Hereās the complete <a href="https://arxiv.org/abs/2207.03517">paper</a>.</p> +<div class="sourceCode" id="cb6"><pre class="sourceCode bibtex code-with-copy"><code class="sourceCode bibtex"><span id="cb6-1"><a href="#cb6-1" aria-hidden="true" tabindex="-1"></a><span class="va">@article</span>{<span class="ot">olivares2022hierarchicalforecast</span>,</span> +<span id="cb6-2"><a href="#cb6-2" aria-hidden="true" tabindex="-1"></a> <span class="dt">author</span> = {Kin G. Olivares and</span> +<span id="cb6-3"><a href="#cb6-3" aria-hidden="true" tabindex="-1"></a> Federico Garza and </span> +<span id="cb6-4"><a href="#cb6-4" aria-hidden="true" tabindex="-1"></a> David Luo and </span> +<span id="cb6-5"><a href="#cb6-5" aria-hidden="true" tabindex="-1"></a> Cristian ChallĆŗ and</span> +<span id="cb6-6"><a href="#cb6-6" aria-hidden="true" tabindex="-1"></a> Max Mergenthaler and</span> +<span id="cb6-7"><a href="#cb6-7" aria-hidden="true" tabindex="-1"></a> Souhaib Ben Taieb and</span> +<span id="cb6-8"><a href="#cb6-8" aria-hidden="true" tabindex="-1"></a> Shanika L. Wickramasuriya and</span> +<span id="cb6-9"><a href="#cb6-9" aria-hidden="true" tabindex="-1"></a> Artur Dubrawski},</span> +<span id="cb6-10"><a href="#cb6-10" aria-hidden="true" tabindex="-1"></a> <span class="dt">title</span> = {{HierarchicalForecast}: A Reference Framework for Hierarchical Forecasting in Python},</span> +<span id="cb6-11"><a href="#cb6-11" aria-hidden="true" tabindex="-1"></a> <span class="dt">journal</span> = {Work in progress paper, submitted to Journal of Machine Learning Research.},</span> +<span id="cb6-12"><a href="#cb6-12" aria-hidden="true" tabindex="-1"></a> <span class="dt">volume</span> = {abs/2207.03517},</span> +<span id="cb6-13"><a href="#cb6-13" aria-hidden="true" tabindex="-1"></a> <span class="dt">year</span> = {2022},</span> +<span id="cb6-14"><a href="#cb6-14" aria-hidden="true" tabindex="-1"></a> <span class="dt">url</span> = {https://arxiv.org/abs/2207.03517},</span> +<span id="cb6-15"><a href="#cb6-15" aria-hidden="true" tabindex="-1"></a> <span class="dt">archivePrefix</span> = {arXiv}</span> +<span id="cb6-16"><a href="#cb6-16" aria-hidden="true" tabindex="-1"></a>}</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> + + +</section> + +<p>If you find the code useful, please ā us on <a href="https://github.com/nixtla/hierarchicalforecast">Github</a></p></main> <!-- /main --> +<script id="quarto-html-after-body" type="application/javascript"> +window.document.addEventListener("DOMContentLoaded", function (event) { + const toggleBodyColorMode = (bsSheetEl) => { + const mode = bsSheetEl.getAttribute("data-mode"); + const bodyEl = window.document.querySelector("body"); + if (mode === "dark") { + bodyEl.classList.add("quarto-dark"); + bodyEl.classList.remove("quarto-light"); + } else { + bodyEl.classList.add("quarto-light"); + bodyEl.classList.remove("quarto-dark"); + } + } + const toggleBodyColorPrimary = () => { + const bsSheetEl = window.document.querySelector("link#quarto-bootstrap"); + if (bsSheetEl) { + toggleBodyColorMode(bsSheetEl); + } + } + toggleBodyColorPrimary(); + const icon = "ī§"; + const anchorJS = new window.AnchorJS(); + anchorJS.options = { + placement: 'right', + icon: icon + }; + anchorJS.add('.anchored'); + const isCodeAnnotation = (el) => { + for (const clz of el.classList) { + if (clz.startsWith('code-annotation-')) { + return true; + } + } + return false; + } + const clipboard = new window.ClipboardJS('.code-copy-button', { + text: function(trigger) { + const codeEl = trigger.previousElementSibling.cloneNode(true); + for (const childEl of codeEl.children) { + if (isCodeAnnotation(childEl)) { + childEl.remove(); + } + } + return codeEl.innerText; + } + }); + clipboard.on('success', function(e) { + // button target + const button = e.trigger; + // don't keep focus + button.blur(); + // flash "checked" + button.classList.add('code-copy-button-checked'); + var currentTitle = button.getAttribute("title"); + button.setAttribute("title", "Copied!"); + let tooltip; + if (window.bootstrap) { + button.setAttribute("data-bs-toggle", "tooltip"); + button.setAttribute("data-bs-placement", "left"); + button.setAttribute("data-bs-title", "Copied!"); + tooltip = new bootstrap.Tooltip(button, + { trigger: "manual", + customClass: "code-copy-button-tooltip", + offset: [0, -8]}); + tooltip.show(); + } + setTimeout(function() { + if (tooltip) { + tooltip.hide(); + button.removeAttribute("data-bs-title"); + button.removeAttribute("data-bs-toggle"); + button.removeAttribute("data-bs-placement"); + } + button.setAttribute("title", currentTitle); + button.classList.remove('code-copy-button-checked'); + }, 1000); + // clear code selection + e.clearSelection(); + }); + function tippyHover(el, contentFn) { + const config = { + allowHTML: true, + content: contentFn, + maxWidth: 500, + delay: 100, + arrow: false, + appendTo: function(el) { + return el.parentElement; + }, + interactive: true, + interactiveBorder: 10, + theme: 'quarto', + placement: 'bottom-start' + }; + window.tippy(el, config); + } + const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]'); + for (var i=0; i<noterefs.length; i++) { + const ref = noterefs[i]; + tippyHover(ref, function() { + // use id or data attribute instead here + let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href'); + try { href = new URL(href).hash; } catch {} + const id = href.replace(/^#\/?/, ""); + const note = window.document.getElementById(id); + return note.innerHTML; + }); + } + let selectedAnnoteEl; + const selectorForAnnotation = ( cell, annotation) => { + let cellAttr = 'data-code-cell="' + cell + '"'; + let lineAttr = 'data-code-annotation="' + annotation + '"'; + const selector = 'span[' + cellAttr + '][' + lineAttr + ']'; + return selector; + } + const selectCodeLines = (annoteEl) => { + const doc = window.document; + const targetCell = annoteEl.getAttribute("data-target-cell"); + const targetAnnotation = annoteEl.getAttribute("data-target-annotation"); + const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation)); + const lines = annoteSpan.getAttribute("data-code-lines").split(","); + const lineIds = lines.map((line) => { + return targetCell + "-" + line; + }) + let top = null; + let height = null; + let parent = null; + if (lineIds.length > 0) { + //compute the position of the single el (top and bottom and make a div) + const el = window.document.getElementById(lineIds[0]); + top = el.offsetTop; + height = el.offsetHeight; + parent = el.parentElement.parentElement; + if (lineIds.length > 1) { + const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]); + const bottom = lastEl.offsetTop + lastEl.offsetHeight; + height = bottom - top; + } + if (top !== null && height !== null && parent !== null) { + // cook up a div (if necessary) and position it + let div = window.document.getElementById("code-annotation-line-highlight"); + if (div === null) { + div = window.document.createElement("div"); + div.setAttribute("id", "code-annotation-line-highlight"); + div.style.position = 'absolute'; + parent.appendChild(div); + } + div.style.top = top - 2 + "px"; + div.style.height = height + 4 + "px"; + let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter"); + if (gutterDiv === null) { + gutterDiv = window.document.createElement("div"); + gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter"); + gutterDiv.style.position = 'absolute'; + const codeCell = window.document.getElementById(targetCell); + const gutter = codeCell.querySelector('.code-annotation-gutter'); + gutter.appendChild(gutterDiv); + } + gutterDiv.style.top = top - 2 + "px"; + gutterDiv.style.height = height + 4 + "px"; + } + selectedAnnoteEl = annoteEl; + } + }; + const unselectCodeLines = () => { + const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"]; + elementsIds.forEach((elId) => { + const div = window.document.getElementById(elId); + if (div) { + div.remove(); + } + }); + selectedAnnoteEl = undefined; + }; + // Attach click handler to the DT + const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); + for (const annoteDlNode of annoteDls) { + annoteDlNode.addEventListener('click', (event) => { + const clickedEl = event.target; + if (clickedEl !== selectedAnnoteEl) { + unselectCodeLines(); + const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active'); + if (activeEl) { + activeEl.classList.remove('code-annotation-active'); + } + selectCodeLines(clickedEl); + clickedEl.classList.add('code-annotation-active'); + } else { + // Unselect the line + unselectCodeLines(); + clickedEl.classList.remove('code-annotation-active'); + } + }); + } + const findCites = (el) => { + const parentEl = el.parentElement; + if (parentEl) { + const cites = parentEl.dataset.cites; + if (cites) { + return { + el, + cites: cites.split(' ') + }; + } else { + return findCites(el.parentElement) + } + } else { + return undefined; + } + }; + var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]'); + for (var i=0; i<bibliorefs.length; i++) { + const ref = bibliorefs[i]; + const citeInfo = findCites(ref); + if (citeInfo) { + tippyHover(citeInfo.el, function() { + var popup = window.document.createElement('div'); + citeInfo.cites.forEach(function(cite) { + var citeDiv = window.document.createElement('div'); + citeDiv.classList.add('hanging-indent'); + citeDiv.classList.add('csl-entry'); + var biblioDiv = window.document.getElementById('ref-' + cite); + if (biblioDiv) { + citeDiv.innerHTML = biblioDiv.innerHTML; + } + popup.appendChild(citeDiv); + }); + return popup.innerHTML; + }); + } + } +}); +</script> +</div> <!-- /content --> + + + +</body></html> \ No newline at end of file diff --git a/listings.json b/listings.json new file mode 100644 index 00000000..71087fd5 --- /dev/null +++ b/listings.json @@ -0,0 +1,19 @@ +[ + { + "listing": "/examples/index.html", + "items": [ + "/examples/australiandomestictourism-bootstraped-intervals.html", + "/examples/australianprisonpopulation.html", + "/examples/australiandomestictourism.html", + "/examples/hierarchicalforecast-gluonts.html", + "/examples/installation.html", + "/examples/introduction.html", + "/examples/mlframeworksexample.html", + "/examples/nonnegativereconciliation.html", + "/examples/australiandomestictourism-intervals.html", + "/examples/australiandomestictourism-permbu-intervals.html", + "/examples/tourismlarge-evaluation.html", + "/examples/tourismsmall.html" + ] + } +] \ No newline at end of file diff --git a/methods.html b/methods.html new file mode 100644 index 00000000..ff8a1801 --- /dev/null +++ b/methods.html @@ -0,0 +1,1221 @@ +<!DOCTYPE html> +<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head> + +<meta charset="utf-8"> +<meta name="generator" content="quarto-1.3.450"> + +<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes"> + + +<title>hierarchicalforecast - Reconciliation Methods </title> +<style> +code{white-space: pre-wrap;} +span.smallcaps{font-variant: small-caps;} +div.columns{display: flex; gap: min(4vw, 1.5em);} +div.column{flex: auto; overflow-x: auto;} +div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;} +ul.task-list{list-style: none;} +ul.task-list li input[type="checkbox"] { + width: 0.8em; + margin: 0 0.8em 0.2em -1em; /* quarto-specific, see https://github.com/quarto-dev/quarto-cli/issues/4556 */ + vertical-align: middle; +} +/* CSS for syntax highlighting */ +pre > code.sourceCode { white-space: pre; position: relative; } +pre > code.sourceCode > span { display: inline-block; line-height: 1.25; } +pre > code.sourceCode > span:empty { height: 1.2em; } +.sourceCode { overflow: visible; } +code.sourceCode > span { color: inherit; text-decoration: inherit; } +div.sourceCode { margin: 1em 0; } +pre.sourceCode { margin: 0; } +@media screen { +div.sourceCode { overflow: auto; } +} +@media print { +pre > code.sourceCode { white-space: pre-wrap; } +pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; } +} +pre.numberSource code + { counter-reset: source-line 0; } +pre.numberSource code > span + { position: relative; left: -4em; counter-increment: source-line; } +pre.numberSource code > span > a:first-child::before + { content: counter(source-line); + position: relative; left: -1em; text-align: right; vertical-align: baseline; + border: none; display: inline-block; + -webkit-touch-callout: none; -webkit-user-select: none; + -khtml-user-select: none; -moz-user-select: none; + -ms-user-select: none; user-select: none; + padding: 0 4px; width: 4em; + } +pre.numberSource { margin-left: 3em; padding-left: 4px; } +div.sourceCode + { } +@media screen { +pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; } +} +</style> + + +<script src="site_libs/quarto-nav/quarto-nav.js"></script> +<script src="site_libs/quarto-nav/headroom.min.js"></script> +<script src="site_libs/clipboard/clipboard.min.js"></script> +<script src="site_libs/quarto-search/autocomplete.umd.js"></script> +<script src="site_libs/quarto-search/fuse.min.js"></script> +<script src="site_libs/quarto-search/quarto-search.js"></script> +<meta name="quarto:offset" content="./"> +<link href="./favicon_png.png" rel="icon" type="image/png"> +<script src="site_libs/quarto-html/quarto.js"></script> +<script src="site_libs/quarto-html/popper.min.js"></script> +<script src="site_libs/quarto-html/tippy.umd.min.js"></script> +<script src="site_libs/quarto-html/anchor.min.js"></script> +<link href="site_libs/quarto-html/tippy.css" rel="stylesheet"> +<link href="site_libs/quarto-html/quarto-syntax-highlighting.css" rel="stylesheet" id="quarto-text-highlighting-styles"> +<script src="site_libs/bootstrap/bootstrap.min.js"></script> +<link href="site_libs/bootstrap/bootstrap-icons.css" rel="stylesheet"> +<link href="site_libs/bootstrap/bootstrap.min.css" rel="stylesheet" id="quarto-bootstrap" data-mode="light"> +<script id="quarto-search-options" type="application/json">{ + "location": "navbar", + "copy-button": false, + "collapse-after": 3, + "panel-placement": "end", + "type": "overlay", + "limit": 20, + "language": { + "search-no-results-text": "No results", + "search-matching-documents-text": "matching documents", + "search-copy-link-title": "Copy link to search", + "search-hide-matches-text": "Hide additional matches", + "search-more-match-text": "more match in this document", + "search-more-matches-text": "more matches in this document", + "search-clear-button-title": "Clear", + "search-detached-cancel-button-title": "Cancel", + "search-submit-button-title": "Submit", + "search-label": "Search" + } +}</script> +<script async="" src="https://www.googletagmanager.com/gtag/js?id=G-NXJNCVR18L"></script> + +<script type="text/javascript"> + +window.dataLayer = window.dataLayer || []; +function gtag(){dataLayer.push(arguments);} +gtag('js', new Date()); +gtag('config', 'G-NXJNCVR18L', { 'anonymize_ip': true}); +</script> + + <script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script> + <script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml-full.js" type="text/javascript"></script> + +<link rel="stylesheet" href="styles.css"> +<meta property="og:title" content="hierarchicalforecast - Reconciliation Methods "> +<meta property="og:description" content=""> +<meta property="og:site-name" content="hierarchicalforecast"> +<meta name="twitter:title" content="hierarchicalforecast - Reconciliation Methods "> +<meta name="twitter:description" content=""> +<meta name="twitter:card" content="summary"> +</head> + +<body class="nav-sidebar floating nav-fixed"> + +<div id="quarto-search-results"></div> + <header id="quarto-header" class="headroom fixed-top"> + <nav class="navbar navbar-expand-lg navbar-dark "> + <div class="navbar-container container-fluid"> + <div class="navbar-brand-container"> + <a class="navbar-brand" href="./index.html"> + <span class="navbar-title">hierarchicalforecast</span> + </a> + </div> + <div id="quarto-search" class="" title="Search"></div> + <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + <span class="navbar-toggler-icon"></span> +</button> + <div class="collapse navbar-collapse" id="navbarCollapse"> + <ul class="navbar-nav navbar-nav-scroll me-auto"> + <li class="nav-item"> + <a class="nav-link active" href="./examples/tourismsmall.html" rel="" target="" aria-current="page"> + <span class="menu-text">Get Started</span></a> + </li> + <li class="nav-item dropdown "> + <a class="nav-link dropdown-toggle" href="#" id="nav-menu-nixtlaverse" role="button" data-bs-toggle="dropdown" aria-expanded="false" rel="" target=""> + <span class="menu-text">NixtlaVerse</span> + </a> + <ul class="dropdown-menu" aria-labelledby="nav-menu-nixtlaverse"> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/mlforecast" rel="" target=""> + <span class="dropdown-text">MLForecast š¤</span></a> + </li> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/neuralforecast" rel="" target=""> + <span class="dropdown-text">NeuralForecast š§ </span></a> + </li> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/statsforecast" rel="" target=""> + <span class="dropdown-text">StatsForecast ā”ļø</span></a> + </li> + </ul> + </li> + <li class="nav-item dropdown "> + <a class="nav-link dropdown-toggle" href="#" id="nav-menu-help" role="button" data-bs-toggle="dropdown" aria-expanded="false" rel="" target=""> + <span class="menu-text">Help</span> + </a> + <ul class="dropdown-menu" aria-labelledby="nav-menu-help"> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/hierarchicalforecast/issues/new/choose" rel="" target=""><i class="bi bi-bug" role="img"> +</i> + <span class="dropdown-text">Report an Issue</span></a> + </li> + <li> + <a class="dropdown-item" href="https://join.slack.com/t/nixtlacommunity/shared_invite/zt-1kd5m5db7-7OOfy0xVNf1PcvCiAPWvPw" rel="" target=""><i class="bi bi-chat-right-text" role="img"> +</i> + <span class="dropdown-text">Join our Slack</span></a> + </li> + </ul> + </li> +</ul> + <ul class="navbar-nav navbar-nav-scroll ms-auto"> + <li class="nav-item compact"> + <a class="nav-link" href="https://github.com/nixtla/hierarchicalforecast" rel="" target=""><i class="bi bi-github" role="img"> +</i> + <span class="menu-text"></span></a> + </li> + <li class="nav-item compact"> + <a class="nav-link" href="https://twitter.com/nixtlainc" rel="" target=""><i class="bi bi-twitter" role="img" aria-label="Nixtla Twitter"> +</i> + <span class="menu-text"></span></a> + </li> +</ul> + <div class="quarto-navbar-tools"> +</div> + </div> <!-- /navcollapse --> + </div> <!-- /container-fluid --> + </nav> + <nav class="quarto-secondary-nav"> + <div class="container-fluid d-flex"> + <button type="button" class="quarto-btn-toggle btn" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + <i class="bi bi-layout-text-sidebar-reverse"></i> + </button> + <nav class="quarto-page-breadcrumbs" aria-label="breadcrumb"><ol class="breadcrumb"><li class="breadcrumb-item"><a href="./core.html">API Reference</a></li><li class="breadcrumb-item"><a href="./methods.html"><span style="color:DarkOrange"> Reconciliation Methods </span></a></li></ol></nav> + <a class="flex-grow-1" role="button" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + </a> + </div> + </nav> +</header> +<!-- content --> +<div id="quarto-content" class="quarto-container page-columns page-rows-contents page-layout-article page-navbar"> +<!-- sidebar --> + <nav id="quarto-sidebar" class="sidebar collapse collapse-horizontal sidebar-navigation floating overflow-auto"> + <div class="sidebar-menu-container"> + <ul class="list-unstyled mt-1"> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./index.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Hierarchical Forecast š</span></a> + </div> +</li> + <li class="px-0"><hr class="sidebar-divider hi "></li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-1" aria-expanded="false"> + <span class="menu-text">Getting Started</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-1" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-1" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/installation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Install</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/tourismsmall.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Reconciliation Quick Start</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/introduction.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Introduction</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-2" aria-expanded="false"> + <span class="menu-text">Tutorials</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-2" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-2" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-3" aria-expanded="false"> + <span class="menu-text">Point Reconciliation</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-3" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-3" class="collapse list-unstyled sidebar-section depth2 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/australiandomestictourism.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Geographical Aggregation (Tourism)</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/australianprisonpopulation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Geographical Aggregation (Prison Population)</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/nonnegativereconciliation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Non-Negative MinTrace</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-4" aria-expanded="false"> + <span class="menu-text">Probabilistic Reconciliation</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-4" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-4" class="collapse list-unstyled sidebar-section depth2 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/australiandomestictourism-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Normality</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/australiandomestictourism-bootstraped-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Bootstrap</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/australiandomestictourism-permbu-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">PERMBU</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/tourismlarge-evaluation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Probabilistic Forecast Evaluation</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-5" aria-expanded="false"> + <span class="menu-text">ML Forecast Reconciliation</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-5" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-5" class="collapse list-unstyled sidebar-section depth2 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/hierarchicalforecast-gluonts.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">GluonTS</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/mlframeworksexample.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Neural/MLForecast</span></a> + </div> +</li> + </ul> + </li> + </ul> + </li> + <li class="sidebar-item"> + <span class="menu-text">Methods</span> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-6" aria-expanded="true"> + <span class="menu-text">API Reference</span></a> + <a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-6" aria-expanded="true" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-6" class="collapse list-unstyled sidebar-section depth1 show"> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./core.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Core </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./methods.html" class="sidebar-item-text sidebar-link active"> + <span class="menu-text"><span style="color:DarkOrange"> Reconciliation Methods </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./probabilistic_methods.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Probabilistic Methods </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./evaluation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Hierarchical Evaluation</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./utils.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Aggregation/Visualization Utils</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-7" aria-expanded="false"> + <span class="menu-text">Community</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-7" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-7" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item"> + <span class="menu-text">Contributing</span> + </li> + </ul> + </li> + </ul> + </div> +</nav> +<div id="quarto-sidebar-glass" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass"></div> +<!-- margin-sidebar --> + <div id="quarto-margin-sidebar" class="sidebar margin-sidebar"> + <nav id="TOC" role="doc-toc" class="toc-active"> + <h2 id="toc-title">On this page</h2> + + <ul> + <li><a href="#bottom-up" id="toc-bottom-up" class="nav-link active" data-scroll-target="#bottom-up"><span style="color:DarkBlue"> 1. Bottom-Up </span></a> + <ul class="collapse"> + <li><a href="#bottomupsparse" id="toc-bottomupsparse" class="nav-link" data-scroll-target="#bottomupsparse">BottomUpSparse</a></li> + <li><a href="#bottomup" id="toc-bottomup" class="nav-link" data-scroll-target="#bottomup">BottomUp</a></li> + <li><a href="#bottomup.fit" id="toc-bottomup.fit" class="nav-link" data-scroll-target="#bottomup.fit">BottomUp.fit</a></li> + <li><a href="#bottomup.predict" id="toc-bottomup.predict" class="nav-link" data-scroll-target="#bottomup.predict">BottomUp.predict</a></li> + <li><a href="#bottomup.fit_predict" id="toc-bottomup.fit_predict" class="nav-link" data-scroll-target="#bottomup.fit_predict">BottomUp.fit_predict</a></li> + <li><a href="#bottomup.sample" id="toc-bottomup.sample" class="nav-link" data-scroll-target="#bottomup.sample">BottomUp.sample</a></li> + </ul></li> + <li><a href="#top-down" id="toc-top-down" class="nav-link" data-scroll-target="#top-down"><span style="color:DarkBlue"> 2. Top-Down </span></a> + <ul class="collapse"> + <li><a href="#topdown" id="toc-topdown" class="nav-link" data-scroll-target="#topdown">TopDown</a></li> + <li><a href="#topdown.fit" id="toc-topdown.fit" class="nav-link" data-scroll-target="#topdown.fit">TopDown.fit</a></li> + <li><a href="#topdown.predict" id="toc-topdown.predict" class="nav-link" data-scroll-target="#topdown.predict">TopDown.predict</a></li> + <li><a href="#topdown.fit_predict" id="toc-topdown.fit_predict" class="nav-link" data-scroll-target="#topdown.fit_predict">TopDown.fit_predict</a></li> + <li><a href="#topdown.sample" id="toc-topdown.sample" class="nav-link" data-scroll-target="#topdown.sample">TopDown.sample</a></li> + </ul></li> + <li><a href="#middle-out" id="toc-middle-out" class="nav-link" data-scroll-target="#middle-out"><span style="color:DarkBlue"> 3. Middle-Out </span></a> + <ul class="collapse"> + <li><a href="#middleout" id="toc-middleout" class="nav-link" data-scroll-target="#middleout">MiddleOut</a></li> + <li><a href="#middleout.fit_predict" id="toc-middleout.fit_predict" class="nav-link" data-scroll-target="#middleout.fit_predict">MiddleOut.fit_predict</a></li> + </ul></li> + <li><a href="#min-trace" id="toc-min-trace" class="nav-link" data-scroll-target="#min-trace"><span style="color:DarkBlue"> 4. Min-Trace </span></a> + <ul class="collapse"> + <li><a href="#mintracesparse" id="toc-mintracesparse" class="nav-link" data-scroll-target="#mintracesparse">MinTraceSparse</a></li> + <li><a href="#mintrace" id="toc-mintrace" class="nav-link" data-scroll-target="#mintrace">MinTrace</a></li> + <li><a href="#mintrace.fit" id="toc-mintrace.fit" class="nav-link" data-scroll-target="#mintrace.fit">MinTrace.fit</a></li> + <li><a href="#mintrace.predict" id="toc-mintrace.predict" class="nav-link" data-scroll-target="#mintrace.predict">MinTrace.predict</a></li> + <li><a href="#mintrace.fit_predict" id="toc-mintrace.fit_predict" class="nav-link" data-scroll-target="#mintrace.fit_predict">MinTrace.fit_predict</a></li> + <li><a href="#mintrace.sample" id="toc-mintrace.sample" class="nav-link" data-scroll-target="#mintrace.sample">MinTrace.sample</a></li> + </ul></li> + <li><a href="#optimal-combination" id="toc-optimal-combination" class="nav-link" data-scroll-target="#optimal-combination"><span style="color:DarkBlue"> 5. Optimal Combination </span></a> + <ul class="collapse"> + <li><a href="#optimalcombination" id="toc-optimalcombination" class="nav-link" data-scroll-target="#optimalcombination">OptimalCombination</a></li> + <li><a href="#optimalcombination.fit" id="toc-optimalcombination.fit" class="nav-link" data-scroll-target="#optimalcombination.fit">OptimalCombination.fit</a></li> + <li><a href="#optimalcombination.predict" id="toc-optimalcombination.predict" class="nav-link" data-scroll-target="#optimalcombination.predict">OptimalCombination.predict</a></li> + <li><a href="#optimalcombination.fit_predict" id="toc-optimalcombination.fit_predict" class="nav-link" data-scroll-target="#optimalcombination.fit_predict">OptimalCombination.fit_predict</a></li> + <li><a href="#optimalcombination.sample" id="toc-optimalcombination.sample" class="nav-link" data-scroll-target="#optimalcombination.sample">OptimalCombination.sample</a></li> + </ul></li> + <li><a href="#emp.-risk-minimization" id="toc-emp.-risk-minimization" class="nav-link" data-scroll-target="#emp.-risk-minimization"><span style="color:DarkBlue"> 6. Emp. Risk Minimization </span></a> + <ul class="collapse"> + <li><a href="#erm" id="toc-erm" class="nav-link" data-scroll-target="#erm">ERM</a></li> + <li><a href="#erm.fit" id="toc-erm.fit" class="nav-link" data-scroll-target="#erm.fit">ERM.fit</a></li> + <li><a href="#erm.predict" id="toc-erm.predict" class="nav-link" data-scroll-target="#erm.predict">ERM.predict</a></li> + <li><a href="#erm.fit_predict" id="toc-erm.fit_predict" class="nav-link" data-scroll-target="#erm.fit_predict">ERM.fit_predict</a></li> + <li><a href="#erm.sample" id="toc-erm.sample" class="nav-link" data-scroll-target="#erm.sample">ERM.sample</a></li> + </ul></li> + <li><a href="#references" id="toc-references" class="nav-link" data-scroll-target="#references"><span style="color:DarkBlue"> References </span></a> + <ul class="collapse"> + <li><a href="#general-reconciliation" id="toc-general-reconciliation" class="nav-link" data-scroll-target="#general-reconciliation">General Reconciliation</a></li> + <li><a href="#optimal-reconciliation" id="toc-optimal-reconciliation" class="nav-link" data-scroll-target="#optimal-reconciliation">Optimal Reconciliation</a></li> + <li><a href="#hierarchical-probabilistic-coherent-predictions" id="toc-hierarchical-probabilistic-coherent-predictions" class="nav-link" data-scroll-target="#hierarchical-probabilistic-coherent-predictions">Hierarchical Probabilistic Coherent Predictions</a></li> + </ul></li> + </ul> +<div class="toc-actions"><div><i class="bi bi-github"></i></div><div class="action-links"><p><a href="https://github.com/Nixtla/hierarchicalforecast/issues/new" class="toc-action">Report an issue</a></p></div></div></nav> + </div> +<!-- main --> +<main class="content" id="quarto-document-content"> + +<header id="title-block-header" class="quarto-title-block default"> +<div class="quarto-title"> +<h1 class="title"><span style="color:DarkOrange"> Reconciliation Methods </span></h1> +</div> + + + +<div class="quarto-title-meta"> + + + + + </div> + + +</header> + +<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! --> +<p>Large collections of time series organized into structures at different aggregation levels often require their forecasts to follow their aggregation constraints, which poses the challenge of creating novel algorithms capable of coherent forecasts. <br><br> The <code>HierarchicalForecast</code> package provides the most comprehensive collection of Python implementations of hierarchical forecasting algorithms that follow classic hierarchical reconciliation. All the methods have a <code>reconcile</code> function capable of reconcile base forecasts using <code>numpy</code> arrays.</p> +<p>Most reconciliation methods can be described by the following convenient linear algebra notation:</p> +<p><span class="math display">\[\tilde{\mathbf{y}}_{[a,b],\tau} = \mathbf{S}_{[a,b][b]} \mathbf{P}_{[b][a,b]} \hat{\mathbf{y}}_{[a,b],\tau}\]</span></p> +<p>where <span class="math inline">\(a, b\)</span> represent the aggregate and bottom levels, <span class="math inline">\(\mathbf{S}_{[a,b][b]}\)</span> contains the hierarchical aggregation constraints, and <span class="math inline">\(\mathbf{P}_{[b][a,b]}\)</span> varies across reconciliation methods. The reconciled predictions are <span class="math inline">\(\tilde{\mathbf{y}}_{[a,b],\tau}\)</span>, and the base predictions <span class="math inline">\(\hat{\mathbf{y}}_{[a,b],\tau}\)</span>.</p> +<section id="bottom-up" class="level1"> +<h1><span style="color:DarkBlue"> 1. Bottom-Up </span></h1> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/methods.py#L232" target="_blank" style="float:right; font-size:smaller">source</a></p> +<section id="bottomupsparse" class="level3"> +<h3 class="anchored" data-anchor-id="bottomupsparse">BottomUpSparse</h3> +<blockquote class="blockquote"> +<pre><code> BottomUpSparse ()</code></pre> +</blockquote> +<p>BottomUpSparse Reconciliation Class.</p> +<p>This is the implementation of a Bottom Up reconciliation using the sparse matrix approach. It works much more efficient on datasets with many time series. [makoren: At least I hope so, I only checked up until ~20k time series, and thereās no real improvement, it would be great to check for smth like 1M time series, where the dense S matrix really stops fitting in memory]</p> +<p>See the parent class for more details.</p> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/methods.py#L127" target="_blank" style="float:right; font-size:smaller">source</a></p> +</section> +<section id="bottomup" class="level3"> +<h3 class="anchored" data-anchor-id="bottomup">BottomUp</h3> +<blockquote class="blockquote"> +<pre><code> BottomUp ()</code></pre> +</blockquote> +<p>Bottom Up Reconciliation Class. The most basic hierarchical reconciliation is performed using an Bottom-Up strategy. It was proposed for the first time by Orcutt in 1968. The corresponding hierarchical āprojectionā matrix is defined as: <span class="math display">\[\mathbf{P}_{\text{BU}} = [\mathbf{0}_{\mathrm{[b],[a]}}\;|\;\mathbf{I}_{\mathrm{[b][b]}}]\]</span></p> +<p><strong>Parameters:</strong><br> None</p> +<p><strong>References:</strong><br> - <a href="http://www.jstor.org/stable/1815532">Orcutt, G.H., Watts, H.W., & Edwards, J.B.(1968). āData aggregation and information lossā. The American Economic Review, 58 , 773{787)</a>.</p> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/methods.py#L151" target="_blank" style="float:right; font-size:smaller">source</a></p> +</section> +<section id="bottomup.fit" class="level3"> +<h3 class="anchored" data-anchor-id="bottomup.fit">BottomUp.fit</h3> +<blockquote class="blockquote"> +<pre><code> BottomUp.fit (S:numpy.ndarray, y_hat:numpy.ndarray, + idx_bottom:numpy.ndarray, + y_insample:Optional[numpy.ndarray]=None, + y_hat_insample:Optional[numpy.ndarray]=None, + sigmah:Optional[numpy.ndarray]=None, + intervals_method:Optional[str]=None, + num_samples:Optional[int]=None, seed:Optional[int]=None, + tags:Dict[str,numpy.ndarray]=None)</code></pre> +</blockquote> +<p>Bottom Up Fit Method.</p> +<p><strong>Parameters:</strong><br> <code>S</code>: Summing matrix of size (<code>base</code>, <code>bottom</code>).<br> <code>y_hat</code>: Forecast values of size (<code>base</code>, <code>horizon</code>).<br> <code>idx_bottom</code>: Indices corresponding to the bottom level of <code>S</code>, size (<code>bottom</code>).<br> <code>level</code>: float list 0-100, confidence levels for prediction intervals.<br> <code>intervals_method</code>: Sampler for prediction intevals, one of <code>normality</code>, <code>bootstrap</code>, <code>permbu</code>.<br> <code>**sampler_kwargs</code>: Coherent sampler instantiation arguments.<br></p> +<p><strong>Returns:</strong><br> <code>self</code>: object, fitted reconciler.</p> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/methods.py#L81" target="_blank" style="float:right; font-size:smaller">source</a></p> +</section> +<section id="bottomup.predict" class="level3"> +<h3 class="anchored" data-anchor-id="bottomup.predict">BottomUp.predict</h3> +<blockquote class="blockquote"> +<pre><code> BottomUp.predict (S:numpy.ndarray, y_hat:numpy.ndarray, + level:Optional[List[int]]=None)</code></pre> +</blockquote> +<p>Predict using reconciler.</p> +<p>Predict using fitted mean and probabilistic reconcilers.</p> +<p><strong>Parameters:</strong><br> <code>S</code>: Summing matrix of size (<code>base</code>, <code>bottom</code>).<br> <code>y_hat</code>: Forecast values of size (<code>base</code>, <code>horizon</code>).<br> <code>level</code>: float list 0-100, confidence levels for prediction intervals.<br></p> +<p><strong>Returns:</strong><br> <code>y_tilde</code>: Reconciliated predictions.</p> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/methods.py#L190" target="_blank" style="float:right; font-size:smaller">source</a></p> +</section> +<section id="bottomup.fit_predict" class="level3"> +<h3 class="anchored" data-anchor-id="bottomup.fit_predict">BottomUp.fit_predict</h3> +<blockquote class="blockquote"> +<pre><code> BottomUp.fit_predict (S:numpy.ndarray, y_hat:numpy.ndarray, + idx_bottom:numpy.ndarray, + y_insample:Optional[numpy.ndarray]=None, + y_hat_insample:Optional[numpy.ndarray]=None, + sigmah:Optional[numpy.ndarray]=None, + level:Optional[List[int]]=None, + intervals_method:Optional[str]=None, + num_samples:Optional[int]=None, + seed:Optional[int]=None, + tags:Dict[str,numpy.ndarray]=None)</code></pre> +</blockquote> +<p>BottomUp Reconciliation Method.</p> +<p><strong>Parameters:</strong><br> <code>S</code>: Summing matrix of size (<code>base</code>, <code>bottom</code>).<br> <code>y_hat</code>: Forecast values of size (<code>base</code>, <code>horizon</code>).<br> <code>idx_bottom</code>: Indices corresponding to the bottom level of <code>S</code>, size (<code>bottom</code>).<br> <code>level</code>: float list 0-100, confidence levels for prediction intervals.<br> <code>intervals_method</code>: Sampler for prediction intevals, one of <code>normality</code>, <code>bootstrap</code>, <code>permbu</code>.<br> <code>**sampler_kwargs</code>: Coherent sampler instantiation arguments.<br></p> +<p><strong>Returns:</strong><br> <code>y_tilde</code>: Reconciliated y_hat using the Bottom Up approach.</p> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/methods.py#L103" target="_blank" style="float:right; font-size:smaller">source</a></p> +</section> +<section id="bottomup.sample" class="level3"> +<h3 class="anchored" data-anchor-id="bottomup.sample">BottomUp.sample</h3> +<blockquote class="blockquote"> +<pre><code> BottomUp.sample (num_samples:int)</code></pre> +</blockquote> +<p>Sample probabilistic coherent distribution.</p> +<p>Generates n samples from a probabilistic coherent distribution. The method uses fitted mean and probabilistic reconcilers, defined by the <code>intervals_method</code> selected during the reconcilerās instantiation. Currently available: <code>normality</code>, <code>bootstrap</code>, <code>permbu</code>.</p> +<p><strong>Parameters:</strong><br> <code>num_samples</code>: int, number of samples generated from coherent distribution.<br></p> +<p><strong>Returns:</strong><br> <code>samples</code>: Coherent samples of size (<code>num_series</code>, <code>horizon</code>, <code>num_samples</code>).</p> +</section> +</section> +<section id="top-down" class="level1"> +<h1><span style="color:DarkBlue"> 2. Top-Down </span></h1> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/methods.py#L289" target="_blank" style="float:right; font-size:smaller">source</a></p> +<section id="topdown" class="level3"> +<h3 class="anchored" data-anchor-id="topdown">TopDown</h3> +<blockquote class="blockquote"> +<pre><code> TopDown (method:str)</code></pre> +</blockquote> +<p>Top Down Reconciliation Class.</p> +<p>The Top Down hierarchical reconciliation method, distributes the total aggregate predictions and decomposes it down the hierarchy using proportions <span class="math inline">\(\mathbf{p}_{\mathrm{[b]}}\)</span> that can be actual historical values or estimated.</p> +<p><span class="math display">\[\mathbf{P}=[\mathbf{p}_{\mathrm{[b]}}\;|\;\mathbf{0}_{\mathrm{[b][a,b\;-1]}}]\]</span> <strong>Parameters:</strong><br> <code>method</code>: One of <code>forecast_proportions</code>, <code>average_proportions</code> and <code>proportion_averages</code>.<br></p> +<p><strong>References:</strong><br> - <a href="https://onlinelibrary.wiley.com/doi/abs/10.1002/for.3980090304">CW. Gross (1990). āDisaggregation methods to expedite product line forecastingā. Journal of Forecasting, 9 , 233ā254. doi:10.1002/for.3980090304</a>.<br> - <a href="https://doi.org/10.1016/S0305-0548(99)00017-9">G. Fliedner (1999). āAn investigation of aggregate variable time series forecast strategies with specific subaggregate time series statistical correlationā. Computers and Operations Research, 26 , 1133ā1149. doi:10.1016/S0305-0548(99)00017-9</a>.</p> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/methods.py#L341" target="_blank" style="float:right; font-size:smaller">source</a></p> +</section> +<section id="topdown.fit" class="level3"> +<h3 class="anchored" data-anchor-id="topdown.fit">TopDown.fit</h3> +<blockquote class="blockquote"> +<pre><code> TopDown.fit (S, y_hat, y_insample:Optional[numpy.ndarray]=None, + y_hat_insample:Optional[numpy.ndarray]=None, + sigmah:Optional[numpy.ndarray]=None, + intervals_method:Optional[str]=None, + num_samples:Optional[int]=None, seed:Optional[int]=None, + tags:Dict[str,numpy.ndarray]=None, + idx_bottom:Optional[numpy.ndarray]=None)</code></pre> +</blockquote> +<p>TopDown Fit Method.</p> +<p><strong>Parameters:</strong><br> <code>S</code>: Summing matrix of size (<code>base</code>, <code>bottom</code>).<br> <code>y_hat</code>: Forecast values of size (<code>base</code>, <code>horizon</code>).<br> <code>tags</code>: Each key is a level and each value its <code>S</code> indices.<br> <code>y_insample</code>: Insample values of size (<code>base</code>, <code>insample_size</code>). Optional for <code>forecast_proportions</code> method.<br> <code>idx_bottom</code>: Indices corresponding to the bottom level of <code>S</code>, size (<code>bottom</code>).<br> <code>level</code>: float list 0-100, confidence levels for prediction intervals.<br> <code>intervals_method</code>: Sampler for prediction intevals, one of <code>normality</code>, <code>bootstrap</code>, <code>permbu</code>.<br> <code>**sampler_kwargs</code>: Coherent sampler instantiation arguments.<br></p> +<p><strong>Returns:</strong><br> <code>self</code>: object, fitted reconciler.</p> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/methods.py#L81" target="_blank" style="float:right; font-size:smaller">source</a></p> +</section> +<section id="topdown.predict" class="level3"> +<h3 class="anchored" data-anchor-id="topdown.predict">TopDown.predict</h3> +<blockquote class="blockquote"> +<pre><code> TopDown.predict (S:numpy.ndarray, y_hat:numpy.ndarray, + level:Optional[List[int]]=None)</code></pre> +</blockquote> +<p>Predict using reconciler.</p> +<p>Predict using fitted mean and probabilistic reconcilers.</p> +<p><strong>Parameters:</strong><br> <code>S</code>: Summing matrix of size (<code>base</code>, <code>bottom</code>).<br> <code>y_hat</code>: Forecast values of size (<code>base</code>, <code>horizon</code>).<br> <code>level</code>: float list 0-100, confidence levels for prediction intervals.<br></p> +<p><strong>Returns:</strong><br> <code>y_tilde</code>: Reconciliated predictions.</p> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/methods.py#L383" target="_blank" style="float:right; font-size:smaller">source</a></p> +</section> +<section id="topdown.fit_predict" class="level3"> +<h3 class="anchored" data-anchor-id="topdown.fit_predict">TopDown.fit_predict</h3> +<blockquote class="blockquote"> +<pre><code> TopDown.fit_predict (S:numpy.ndarray, y_hat:numpy.ndarray, + tags:Dict[str,numpy.ndarray], + idx_bottom:numpy.ndarray=None, + y_insample:Optional[numpy.ndarray]=None, + y_hat_insample:Optional[numpy.ndarray]=None, + sigmah:Optional[numpy.ndarray]=None, + level:Optional[List[int]]=None, + intervals_method:Optional[str]=None, + num_samples:Optional[int]=None, + seed:Optional[int]=None)</code></pre> +</blockquote> +<p>Top Down Reconciliation Method.</p> +<p><strong>Parameters:</strong><br> <code>S</code>: Summing matrix of size (<code>base</code>, <code>bottom</code>).<br> <code>y_hat</code>: Forecast values of size (<code>base</code>, <code>horizon</code>).<br> <code>tags</code>: Each key is a level and each value its <code>S</code> indices.<br> <code>y_insample</code>: Insample values of size (<code>base</code>, <code>insample_size</code>). Optional for <code>forecast_proportions</code> method.<br> <code>idx_bottom</code>: Indices corresponding to the bottom level of <code>S</code>, size (<code>bottom</code>).<br> <code>level</code>: float list 0-100, confidence levels for prediction intervals.<br> <code>intervals_method</code>: Sampler for prediction intevals, one of <code>normality</code>, <code>bootstrap</code>, <code>permbu</code>.<br> <code>**sampler_kwargs</code>: Coherent sampler instantiation arguments.<br></p> +<p><strong>Returns:</strong><br> <code>y_tilde</code>: Reconciliated y_hat using the Top Down approach.</p> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/methods.py#L103" target="_blank" style="float:right; font-size:smaller">source</a></p> +</section> +<section id="topdown.sample" class="level3"> +<h3 class="anchored" data-anchor-id="topdown.sample">TopDown.sample</h3> +<blockquote class="blockquote"> +<pre><code> TopDown.sample (num_samples:int)</code></pre> +</blockquote> +<p>Sample probabilistic coherent distribution.</p> +<p>Generates n samples from a probabilistic coherent distribution. The method uses fitted mean and probabilistic reconcilers, defined by the <code>intervals_method</code> selected during the reconcilerās instantiation. Currently available: <code>normality</code>, <code>bootstrap</code>, <code>permbu</code>.</p> +<p><strong>Parameters:</strong><br> <code>num_samples</code>: int, number of samples generated from coherent distribution.<br></p> +<p><strong>Returns:</strong><br> <code>samples</code>: Coherent samples of size (<code>num_series</code>, <code>horizon</code>, <code>num_samples</code>).</p> +</section> +</section> +<section id="middle-out" class="level1"> +<h1><span style="color:DarkBlue"> 3. Middle-Out </span></h1> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/methods.py#L440" target="_blank" style="float:right; font-size:smaller">source</a></p> +<section id="middleout" class="level3"> +<h3 class="anchored" data-anchor-id="middleout">MiddleOut</h3> +<blockquote class="blockquote"> +<pre><code> MiddleOut (middle_level:str, top_down_method:str)</code></pre> +</blockquote> +<p>Middle Out Reconciliation Class.</p> +<p>This method is only available for <strong>strictly hierarchical structures</strong>. It anchors the base predictions in a middle level. The levels above the base predictions use the Bottom-Up approach, while the levels below use a Top-Down.</p> +<p><strong>Parameters:</strong><br> <code>middle_level</code>: Middle level.<br> <code>top_down_method</code>: One of <code>forecast_proportions</code>, <code>average_proportions</code> and <code>proportion_averages</code>.<br></p> +<p><strong>References:</strong><br> - <a href="https://otexts.com/fpp3/hierarchical.html">Hyndman, R.J., & Athanasopoulos, G. (2021). āForecasting: principles and practice, 3rd edition: Chapter 11: Forecasting hierarchical and grouped series.ā. OTexts: Melbourne, Australia. OTexts.com/fpp3 Accessed on July 2022.</a></p> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/methods.py#L473" target="_blank" style="float:right; font-size:smaller">source</a></p> +</section> +<section id="middleout.fit_predict" class="level3"> +<h3 class="anchored" data-anchor-id="middleout.fit_predict">MiddleOut.fit_predict</h3> +<blockquote class="blockquote"> +<pre><code> MiddleOut.fit_predict (S:numpy.ndarray, y_hat:numpy.ndarray, + tags:Dict[str,numpy.ndarray], + y_insample:Optional[numpy.ndarray]=None, + level:Optional[List[int]]=None, + intervals_method:Optional[str]=None)</code></pre> +</blockquote> +<p>Middle Out Reconciliation Method.</p> +<p><strong>Parameters:</strong><br> <code>S</code>: Summing matrix of size (<code>base</code>, <code>bottom</code>).<br> <code>y_hat</code>: Forecast values of size (<code>base</code>, <code>horizon</code>).<br> <code>tags</code>: Each key is a level and each value its <code>S</code> indices.<br> <code>y_insample</code>: Insample values of size (<code>base</code>, <code>insample_size</code>). Only used for <code>forecast_proportions</code><br></p> +<p><strong>Returns:</strong><br> <code>y_tilde</code>: Reconciliated y_hat using the Middle Out approach.</p> +</section> +</section> +<section id="min-trace" class="level1"> +<h1><span style="color:DarkBlue"> 4. Min-Trace </span></h1> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/methods.py#L801" target="_blank" style="float:right; font-size:smaller">source</a></p> +<section id="mintracesparse" class="level3"> +<h3 class="anchored" data-anchor-id="mintracesparse">MinTraceSparse</h3> +<blockquote class="blockquote"> +<pre><code> MinTraceSparse (method:str, nonnegative:bool=False, + mint_shr_ridge:Optional[float]=2e-08)</code></pre> +</blockquote> +<p>MinTraceSparse Reconciliation Class.</p> +<p>This is the implementation of a subset of MinTrace features using the sparse matrix approach. It works much more efficient on datasets with many time series.</p> +<p>See the parent class for more details.</p> +<p>Currently supported: * Methods using diagonal W matrix, i.e. āolsā, āwls_structā, āwls_varā, * The standard MinT version (non-negative is not supported).</p> +<p>Note: due to the numerical instability of the matrix inversion when creating the P matrix, the method is NOT guaranteed to give identical results to the non-sparse version.</p> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/methods.py#L560" target="_blank" style="float:right; font-size:smaller">source</a></p> +</section> +<section id="mintrace" class="level3"> +<h3 class="anchored" data-anchor-id="mintrace">MinTrace</h3> +<blockquote class="blockquote"> +<pre><code> MinTrace (method:str, nonnegative:bool=False, + mint_shr_ridge:Optional[float]=2e-08)</code></pre> +</blockquote> +<p>MinTrace Reconciliation Class.</p> +<p>This reconciliation algorithm proposed by Wickramasuriya et al. depends on a generalized least squares estimator and an estimator of the covariance matrix of the coherency errors <span class="math inline">\(\mathbf{W}_{h}\)</span>. The Min Trace algorithm minimizes the squared errors for the coherent forecasts under an unbiasedness assumption; the solution has a closed form.<br></p> +<p><span class="math display">\[\mathbf{P}_{\text{MinT}}=\left(\mathbf{S}^{\intercal}\mathbf{W}_{h}\mathbf{S}\right)^{-1} +\mathbf{S}^{\intercal}\mathbf{W}^{-1}_{h}\]</span></p> +<p><strong>Parameters:</strong><br> <code>method</code>: str, one of <code>ols</code>, <code>wls_struct</code>, <code>wls_var</code>, <code>mint_shrink</code>, <code>mint_cov</code>.<br> <code>nonnegative</code>: bool, reconciled forecasts should be nonnegative?<br> <code>mint_shr_ridge</code>: float=2e-8, ridge numeric protection to MinTrace-shr covariance estimator.<br></p> +<p><strong>References:</strong><br> - <a href="https://robjhyndman.com/publications/mint/">Wickramasuriya, S. L., Athanasopoulos, G., & Hyndman, R. J. (2019). āOptimal forecast reconciliation for hierarchical and grouped time series through trace minimizationā. Journal of the American Statistical Association, 114 , 804ā819. doi:10.1080/01621459.2018.1448825.</a>. - <a href="https://robjhyndman.com/publications/nnmint/">Wickramasuriya, S.L., Turlach, B.A. & Hyndman, R.J. (2020). āOptimal non-negative forecast reconciliationā. Stat Comput 30, 1167ā1182, https://doi.org/10.1007/s11222-020-09930-0</a>.</p> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/methods.py#L677" target="_blank" style="float:right; font-size:smaller">source</a></p> +</section> +<section id="mintrace.fit" class="level3"> +<h3 class="anchored" data-anchor-id="mintrace.fit">MinTrace.fit</h3> +<blockquote class="blockquote"> +<pre><code> MinTrace.fit (S, y_hat, y_insample:Optional[numpy.ndarray]=None, + y_hat_insample:Optional[numpy.ndarray]=None, + sigmah:Optional[numpy.ndarray]=None, + intervals_method:Optional[str]=None, + num_samples:Optional[int]=None, seed:Optional[int]=None, + tags:Dict[str,numpy.ndarray]=None, + idx_bottom:Optional[numpy.ndarray]=None)</code></pre> +</blockquote> +<p>MinTrace Fit Method.</p> +<p><strong>Parameters:</strong><br> <code>S</code>: Summing matrix of size (<code>base</code>, <code>bottom</code>).<br> <code>y_hat</code>: Forecast values of size (<code>base</code>, <code>horizon</code>).<br> <code>tags</code>: Each key is a level and each value its <code>S</code> indices.<br> <code>y_insample</code>: Insample values of size (<code>base</code>, <code>insample_size</code>). Optional for <code>forecast_proportions</code> method.<br> <code>idx_bottom</code>: Indices corresponding to the bottom level of <code>S</code>, size (<code>bottom</code>).<br> <code>level</code>: float list 0-100, confidence levels for prediction intervals.<br> <code>intervals_method</code>: Sampler for prediction intevals, one of <code>normality</code>, <code>bootstrap</code>, <code>permbu</code>.<br> <code>**sampler_kwargs</code>: Coherent sampler instantiation arguments.<br></p> +<p><strong>Returns:</strong><br> <code>self</code>: object, fitted reconciler.</p> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/methods.py#L81" target="_blank" style="float:right; font-size:smaller">source</a></p> +</section> +<section id="mintrace.predict" class="level3"> +<h3 class="anchored" data-anchor-id="mintrace.predict">MinTrace.predict</h3> +<blockquote class="blockquote"> +<pre><code> MinTrace.predict (S:numpy.ndarray, y_hat:numpy.ndarray, + level:Optional[List[int]]=None)</code></pre> +</blockquote> +<p>Predict using reconciler.</p> +<p>Predict using fitted mean and probabilistic reconcilers.</p> +<p><strong>Parameters:</strong><br> <code>S</code>: Summing matrix of size (<code>base</code>, <code>bottom</code>).<br> <code>y_hat</code>: Forecast values of size (<code>base</code>, <code>horizon</code>).<br> <code>level</code>: float list 0-100, confidence levels for prediction intervals.<br></p> +<p><strong>Returns:</strong><br> <code>y_tilde</code>: Reconciliated predictions.</p> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/methods.py#L752" target="_blank" style="float:right; font-size:smaller">source</a></p> +</section> +<section id="mintrace.fit_predict" class="level3"> +<h3 class="anchored" data-anchor-id="mintrace.fit_predict">MinTrace.fit_predict</h3> +<blockquote class="blockquote"> +<pre><code> MinTrace.fit_predict (S:numpy.ndarray, y_hat:numpy.ndarray, + idx_bottom:numpy.ndarray=None, + y_insample:Optional[numpy.ndarray]=None, + y_hat_insample:Optional[numpy.ndarray]=None, + sigmah:Optional[numpy.ndarray]=None, + level:Optional[List[int]]=None, + intervals_method:Optional[str]=None, + num_samples:Optional[int]=None, + seed:Optional[int]=None, + tags:Dict[str,numpy.ndarray]=None)</code></pre> +</blockquote> +<p>MinTrace Reconciliation Method.</p> +<p><strong>Parameters:</strong><br> <code>S</code>: Summing matrix of size (<code>base</code>, <code>bottom</code>).<br> <code>y_hat</code>: Forecast values of size (<code>base</code>, <code>horizon</code>).<br> <code>y_insample</code>: Insample values of size (<code>base</code>, <code>insample_size</code>). Only used by <code>wls_var</code>, <code>mint_cov</code>, <code>mint_shrink</code><br> <code>y_hat_insample</code>: Insample fitted values of size (<code>base</code>, <code>insample_size</code>). Only used by <code>wls_var</code>, <code>mint_cov</code>, <code>mint_shrink</code><br> <code>idx_bottom</code>: Indices corresponding to the bottom level of <code>S</code>, size (<code>bottom</code>).<br> <code>level</code>: float list 0-100, confidence levels for prediction intervals.<br> <code>sampler</code>: Sampler for prediction intevals, one of <code>normality</code>, <code>bootstrap</code>, <code>permbu</code>.<br></p> +<p><strong>Returns:</strong><br> <code>y_tilde</code>: Reconciliated y_hat using the MinTrace approach.</p> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/methods.py#L103" target="_blank" style="float:right; font-size:smaller">source</a></p> +</section> +<section id="mintrace.sample" class="level3"> +<h3 class="anchored" data-anchor-id="mintrace.sample">MinTrace.sample</h3> +<blockquote class="blockquote"> +<pre><code> MinTrace.sample (num_samples:int)</code></pre> +</blockquote> +<p>Sample probabilistic coherent distribution.</p> +<p>Generates n samples from a probabilistic coherent distribution. The method uses fitted mean and probabilistic reconcilers, defined by the <code>intervals_method</code> selected during the reconcilerās instantiation. Currently available: <code>normality</code>, <code>bootstrap</code>, <code>permbu</code>.</p> +<p><strong>Parameters:</strong><br> <code>num_samples</code>: int, number of samples generated from coherent distribution.<br></p> +<p><strong>Returns:</strong><br> <code>samples</code>: Coherent samples of size (<code>num_series</code>, <code>horizon</code>, <code>num_samples</code>).</p> +</section> +</section> +<section id="optimal-combination" class="level1"> +<h1><span style="color:DarkBlue"> 5. Optimal Combination </span></h1> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/methods.py#L911" target="_blank" style="float:right; font-size:smaller">source</a></p> +<section id="optimalcombination" class="level3"> +<h3 class="anchored" data-anchor-id="optimalcombination">OptimalCombination</h3> +<blockquote class="blockquote"> +<pre><code> OptimalCombination (method:str, nonnegative:bool=False)</code></pre> +</blockquote> +<p>Optimal Combination Reconciliation Class.</p> +<p>This reconciliation algorithm was proposed by Hyndman et al. 2011, the method uses generalized least squares estimator using the coherency errors covariance matrix. Consider the covariance of the base forecast <span class="math inline">\(\textrm{Var}(\epsilon_{h}) = \Sigma_{h}\)</span>, the <span class="math inline">\(\mathbf{P}\)</span> matrix of this method is defined by: <span class="math display">\[ \mathbf{P} = \left(\mathbf{S}^{\intercal}\Sigma_{h}^{\dagger}\mathbf{S}\right)^{-1}\mathbf{S}^{\intercal}\Sigma^{\dagger}_{h}\]</span> where <span class="math inline">\(\Sigma_{h}^{\dagger}\)</span> denotes the variance pseudo-inverse. The method was later proven equivalent to <a href="https://Nixtla.github.io/hierarchicalforecast/methods.html#mintrace"><code>MinTrace</code></a> variants.</p> +<p><strong>Parameters:</strong><br> <code>method</code>: str, allowed optimal combination methods: āolsā, āwls_structā.<br> <code>nonnegative</code>: bool, reconciled forecasts should be nonnegative?<br></p> +<p><strong>References:</strong><br> - <a href="https://robjhyndman.com/papers/Hierarchical6.pdf">Rob J. Hyndman, Roman A. Ahmed, George Athanasopoulos, Han Lin Shang (2010). āOptimal Combination Forecasts for Hierarchical Time Seriesā.</a>.<br> - <a href="https://robjhyndman.com/papers/MinT.pdf">Shanika L. Wickramasuriya, George Athanasopoulos and Rob J. Hyndman (2010). āOptimal Combination Forecasts for Hierarchical Time Seriesā.</a>. - <a href="https://robjhyndman.com/publications/nnmint/">Wickramasuriya, S.L., Turlach, B.A. & Hyndman, R.J. (2020). āOptimal non-negative forecast reconciliationā. Stat Comput 30, 1167ā1182, https://doi.org/10.1007/s11222-020-09930-0</a>.</p> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/methods.py#L677" target="_blank" style="float:right; font-size:smaller">source</a></p> +</section> +<section id="optimalcombination.fit" class="level3"> +<h3 class="anchored" data-anchor-id="optimalcombination.fit">OptimalCombination.fit</h3> +<blockquote class="blockquote"> +<pre><code> OptimalCombination.fit (S, y_hat, + y_insample:Optional[numpy.ndarray]=None, + y_hat_insample:Optional[numpy.ndarray]=None, + sigmah:Optional[numpy.ndarray]=None, + intervals_method:Optional[str]=None, + num_samples:Optional[int]=None, + seed:Optional[int]=None, + tags:Dict[str,numpy.ndarray]=None, + idx_bottom:Optional[numpy.ndarray]=None)</code></pre> +</blockquote> +<p>MinTrace Fit Method.</p> +<p><strong>Parameters:</strong><br> <code>S</code>: Summing matrix of size (<code>base</code>, <code>bottom</code>).<br> <code>y_hat</code>: Forecast values of size (<code>base</code>, <code>horizon</code>).<br> <code>tags</code>: Each key is a level and each value its <code>S</code> indices.<br> <code>y_insample</code>: Insample values of size (<code>base</code>, <code>insample_size</code>). Optional for <code>forecast_proportions</code> method.<br> <code>idx_bottom</code>: Indices corresponding to the bottom level of <code>S</code>, size (<code>bottom</code>).<br> <code>level</code>: float list 0-100, confidence levels for prediction intervals.<br> <code>intervals_method</code>: Sampler for prediction intevals, one of <code>normality</code>, <code>bootstrap</code>, <code>permbu</code>.<br> <code>**sampler_kwargs</code>: Coherent sampler instantiation arguments.<br></p> +<p><strong>Returns:</strong><br> <code>self</code>: object, fitted reconciler.</p> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/methods.py#L81" target="_blank" style="float:right; font-size:smaller">source</a></p> +</section> +<section id="optimalcombination.predict" class="level3"> +<h3 class="anchored" data-anchor-id="optimalcombination.predict">OptimalCombination.predict</h3> +<blockquote class="blockquote"> +<pre><code> OptimalCombination.predict (S:numpy.ndarray, y_hat:numpy.ndarray, + level:Optional[List[int]]=None)</code></pre> +</blockquote> +<p>Predict using reconciler.</p> +<p>Predict using fitted mean and probabilistic reconcilers.</p> +<p><strong>Parameters:</strong><br> <code>S</code>: Summing matrix of size (<code>base</code>, <code>bottom</code>).<br> <code>y_hat</code>: Forecast values of size (<code>base</code>, <code>horizon</code>).<br> <code>level</code>: float list 0-100, confidence levels for prediction intervals.<br></p> +<p><strong>Returns:</strong><br> <code>y_tilde</code>: Reconciliated predictions.</p> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/methods.py#L752" target="_blank" style="float:right; font-size:smaller">source</a></p> +</section> +<section id="optimalcombination.fit_predict" class="level3"> +<h3 class="anchored" data-anchor-id="optimalcombination.fit_predict">OptimalCombination.fit_predict</h3> +<blockquote class="blockquote"> +<pre><code> OptimalCombination.fit_predict (S:numpy.ndarray, y_hat:numpy.ndarray, + idx_bottom:numpy.ndarray=None, + y_insample:Optional[numpy.ndarray]=None, + y_hat_insample:Optional[numpy.ndarray]=No + ne, sigmah:Optional[numpy.ndarray]=None, + level:Optional[List[int]]=None, + intervals_method:Optional[str]=None, + num_samples:Optional[int]=None, + seed:Optional[int]=None, + tags:Dict[str,numpy.ndarray]=None)</code></pre> +</blockquote> +<p>MinTrace Reconciliation Method.</p> +<p><strong>Parameters:</strong><br> <code>S</code>: Summing matrix of size (<code>base</code>, <code>bottom</code>).<br> <code>y_hat</code>: Forecast values of size (<code>base</code>, <code>horizon</code>).<br> <code>y_insample</code>: Insample values of size (<code>base</code>, <code>insample_size</code>). Only used by <code>wls_var</code>, <code>mint_cov</code>, <code>mint_shrink</code><br> <code>y_hat_insample</code>: Insample fitted values of size (<code>base</code>, <code>insample_size</code>). Only used by <code>wls_var</code>, <code>mint_cov</code>, <code>mint_shrink</code><br> <code>idx_bottom</code>: Indices corresponding to the bottom level of <code>S</code>, size (<code>bottom</code>).<br> <code>level</code>: float list 0-100, confidence levels for prediction intervals.<br> <code>sampler</code>: Sampler for prediction intevals, one of <code>normality</code>, <code>bootstrap</code>, <code>permbu</code>.<br></p> +<p><strong>Returns:</strong><br> <code>y_tilde</code>: Reconciliated y_hat using the MinTrace approach.</p> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/methods.py#L103" target="_blank" style="float:right; font-size:smaller">source</a></p> +</section> +<section id="optimalcombination.sample" class="level3"> +<h3 class="anchored" data-anchor-id="optimalcombination.sample">OptimalCombination.sample</h3> +<blockquote class="blockquote"> +<pre><code> OptimalCombination.sample (num_samples:int)</code></pre> +</blockquote> +<p>Sample probabilistic coherent distribution.</p> +<p>Generates n samples from a probabilistic coherent distribution. The method uses fitted mean and probabilistic reconcilers, defined by the <code>intervals_method</code> selected during the reconcilerās instantiation. Currently available: <code>normality</code>, <code>bootstrap</code>, <code>permbu</code>.</p> +<p><strong>Parameters:</strong><br> <code>num_samples</code>: int, number of samples generated from coherent distribution.<br></p> +<p><strong>Returns:</strong><br> <code>samples</code>: Coherent samples of size (<code>num_series</code>, <code>horizon</code>, <code>num_samples</code>).</p> +</section> +</section> +<section id="emp.-risk-minimization" class="level1"> +<h1><span style="color:DarkBlue"> 6. Emp. Risk Minimization </span></h1> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/methods.py#L978" target="_blank" style="float:right; font-size:smaller">source</a></p> +<section id="erm" class="level3"> +<h3 class="anchored" data-anchor-id="erm">ERM</h3> +<blockquote class="blockquote"> +<pre><code> ERM (method:str, lambda_reg:float=0.01)</code></pre> +</blockquote> +<p>Optimal Combination Reconciliation Class.</p> +<p>The Empirical Risk Minimization reconciliation strategy relaxes the unbiasedness assumptions from previous reconciliation methods like MinT and optimizes square errors between the reconciled predictions and the validation data to obtain an optimal reconciliation matrix P.</p> +<p>The exact solution for <span class="math inline">\(\mathbf{P}\)</span> (<code>method='closed'</code>) follows the expression: <span class="math display">\[\mathbf{P}^{*} = \left(\mathbf{S}^{\intercal}\mathbf{S}\right)^{-1}\mathbf{Y}^{\intercal}\hat{\mathbf{Y}}\left(\hat{\mathbf{Y}}\hat{\mathbf{Y}}\right)^{-1}\]</span></p> +<p>The alternative Lasso regularized <span class="math inline">\(\mathbf{P}\)</span> solution (<code>method='reg_bu'</code>) is useful when the observations of validation data is limited or the exact solution has low numerical stability. <span class="math display">\[\mathbf{P}^{*} = \text{argmin}_{\mathbf{P}} ||\mathbf{Y}-\mathbf{S} \mathbf{P} \hat{Y} ||^{2}_{2} + \lambda ||\mathbf{P}-\mathbf{P}_{\text{BU}}||_{1}\]</span></p> +<p><strong>Parameters:</strong><br> <code>method</code>: str, one of <code>closed</code>, <code>reg</code> and <code>reg_bu</code>.<br> <code>lambda_reg</code>: float, l1 regularizer for <code>reg</code> and <code>reg_bu</code>.<br></p> +<p><strong>References:</strong><br> - <a href="https://doi.org/10.1145/3292500.3330976">Ben Taieb, S., & Koo, B. (2019). Regularized regression for hierarchical forecasting without unbiasedness conditions. In Proceedings of the 25th ACM SIGKDD International Conference on Knowledge Discovery & Data Mining KDD ā19 (p. 1337{1347). New York, NY, USA: Association for Computing Machinery.</a>.<br></p> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/methods.py#L1052" target="_blank" style="float:right; font-size:smaller">source</a></p> +</section> +<section id="erm.fit" class="level3"> +<h3 class="anchored" data-anchor-id="erm.fit">ERM.fit</h3> +<blockquote class="blockquote"> +<pre><code> ERM.fit (S, y_hat, y_insample, y_hat_insample, + sigmah:Optional[numpy.ndarray]=None, + intervals_method:Optional[str]=None, + num_samples:Optional[int]=None, seed:Optional[int]=None, + tags:Dict[str,numpy.ndarray]=None, + idx_bottom:Optional[numpy.ndarray]=None)</code></pre> +</blockquote> +<p>ERM Fit Method.</p> +<p><strong>Parameters:</strong><br> <code>S</code>: Summing matrix of size (<code>base</code>, <code>bottom</code>).<br> <code>y_hat</code>: Forecast values of size (<code>base</code>, <code>horizon</code>).<br> <code>y_insample</code>: Train values of size (<code>base</code>, <code>insample_size</code>).<br> <code>y_hat_insample</code>: Insample train predictions of size (<code>base</code>, <code>insample_size</code>).<br> <code>idx_bottom</code>: Indices corresponding to the bottom level of <code>S</code>, size (<code>bottom</code>).<br> <code>level</code>: float list 0-100, confidence levels for prediction intervals.<br> <code>intervals_method</code>: Sampler for prediction intevals, one of <code>normality</code>, <code>bootstrap</code>, <code>permbu</code>.<br> <code>**sampler_kwargs</code>: Coherent sampler instantiation arguments.<br></p> +<p><strong>Returns:</strong><br> <code>self</code>: object, fitted reconciler.</p> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/methods.py#L81" target="_blank" style="float:right; font-size:smaller">source</a></p> +</section> +<section id="erm.predict" class="level3"> +<h3 class="anchored" data-anchor-id="erm.predict">ERM.predict</h3> +<blockquote class="blockquote"> +<pre><code> ERM.predict (S:numpy.ndarray, y_hat:numpy.ndarray, + level:Optional[List[int]]=None)</code></pre> +</blockquote> +<p>Predict using reconciler.</p> +<p>Predict using fitted mean and probabilistic reconcilers.</p> +<p><strong>Parameters:</strong><br> <code>S</code>: Summing matrix of size (<code>base</code>, <code>bottom</code>).<br> <code>y_hat</code>: Forecast values of size (<code>base</code>, <code>horizon</code>).<br> <code>level</code>: float list 0-100, confidence levels for prediction intervals.<br></p> +<p><strong>Returns:</strong><br> <code>y_tilde</code>: Reconciliated predictions.</p> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/methods.py#L1097" target="_blank" style="float:right; font-size:smaller">source</a></p> +</section> +<section id="erm.fit_predict" class="level3"> +<h3 class="anchored" data-anchor-id="erm.fit_predict">ERM.fit_predict</h3> +<blockquote class="blockquote"> +<pre><code> ERM.fit_predict (S:numpy.ndarray, y_hat:numpy.ndarray, + idx_bottom:numpy.ndarray=None, + y_insample:Optional[numpy.ndarray]=None, + y_hat_insample:Optional[numpy.ndarray]=None, + sigmah:Optional[numpy.ndarray]=None, + level:Optional[List[int]]=None, + intervals_method:Optional[str]=None, + num_samples:Optional[int]=None, seed:Optional[int]=None, + tags:Dict[str,numpy.ndarray]=None)</code></pre> +</blockquote> +<p>ERM Reconciliation Method.</p> +<p><strong>Parameters:</strong><br> <code>S</code>: Summing matrix of size (<code>base</code>, <code>bottom</code>).<br> <code>y_hat</code>: Forecast values of size (<code>base</code>, <code>horizon</code>).<br> <code>y_insample</code>: Train values of size (<code>base</code>, <code>insample_size</code>).<br> <code>y_hat_insample</code>: Insample train predictions of size (<code>base</code>, <code>insample_size</code>).<br> <code>idx_bottom</code>: Indices corresponding to the bottom level of <code>S</code>, size (<code>bottom</code>).<br> <code>level</code>: float list 0-100, confidence levels for prediction intervals.<br> <code>intervals_method</code>: Sampler for prediction intevals, one of <code>normality</code>, <code>bootstrap</code>, <code>permbu</code>.<br></p> +<p><strong>Returns:</strong><br> <code>y_tilde</code>: Reconciliated y_hat using the ERM approach.</p> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/methods.py#L103" target="_blank" style="float:right; font-size:smaller">source</a></p> +</section> +<section id="erm.sample" class="level3"> +<h3 class="anchored" data-anchor-id="erm.sample">ERM.sample</h3> +<blockquote class="blockquote"> +<pre><code> ERM.sample (num_samples:int)</code></pre> +</blockquote> +<p>Sample probabilistic coherent distribution.</p> +<p>Generates n samples from a probabilistic coherent distribution. The method uses fitted mean and probabilistic reconcilers, defined by the <code>intervals_method</code> selected during the reconcilerās instantiation. Currently available: <code>normality</code>, <code>bootstrap</code>, <code>permbu</code>.</p> +<p><strong>Parameters:</strong><br> <code>num_samples</code>: int, number of samples generated from coherent distribution.<br></p> +<p><strong>Returns:</strong><br> <code>samples</code>: Coherent samples of size (<code>num_series</code>, <code>horizon</code>, <code>num_samples</code>).</p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb30"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb30-1"><a href="#cb30-1" aria-hidden="true" tabindex="-1"></a>reconciler_args <span class="op">=</span> <span class="bu">dict</span>(S<span class="op">=</span>S, </span> +<span id="cb30-2"><a href="#cb30-2" aria-hidden="true" tabindex="-1"></a> y_hat<span class="op">=</span>y_hat_base,</span> +<span id="cb30-3"><a href="#cb30-3" aria-hidden="true" tabindex="-1"></a> y_insample<span class="op">=</span>y_base,</span> +<span id="cb30-4"><a href="#cb30-4" aria-hidden="true" tabindex="-1"></a> y_hat_insample<span class="op">=</span>y_hat_base_insample,</span> +<span id="cb30-5"><a href="#cb30-5" aria-hidden="true" tabindex="-1"></a> sigmah<span class="op">=</span>sigmah,</span> +<span id="cb30-6"><a href="#cb30-6" aria-hidden="true" tabindex="-1"></a> level<span class="op">=</span>[<span class="dv">80</span>, <span class="dv">90</span>],</span> +<span id="cb30-7"><a href="#cb30-7" aria-hidden="true" tabindex="-1"></a> intervals_method<span class="op">=</span><span class="st">'normality'</span>,</span> +<span id="cb30-8"><a href="#cb30-8" aria-hidden="true" tabindex="-1"></a> num_samples<span class="op">=</span><span class="dv">200</span>,</span> +<span id="cb30-9"><a href="#cb30-9" aria-hidden="true" tabindex="-1"></a> seed<span class="op">=</span><span class="dv">0</span>,</span> +<span id="cb30-10"><a href="#cb30-10" aria-hidden="true" tabindex="-1"></a> tags<span class="op">=</span>tags,</span> +<span id="cb30-11"><a href="#cb30-11" aria-hidden="true" tabindex="-1"></a> idx_bottom<span class="op">=</span>idx_bottom</span> +<span id="cb30-12"><a href="#cb30-12" aria-hidden="true" tabindex="-1"></a> )</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +</section> +</section> +<section id="references" class="level1"> +<h1><span style="color:DarkBlue"> References </span></h1> +<section id="general-reconciliation" class="level3"> +<h3 class="anchored" data-anchor-id="general-reconciliation">General Reconciliation</h3> +<ul> +<li><a href="http://www.jstor.org/stable/1815532">Orcutt, G.H., Watts, H.W., & Edwards, J.B.(1968). Data aggregation and information loss. The American Economic Review, 58 , 773{787).</a><br></li> +<li><a href="https://onlinelibrary.wiley.com/doi/abs/10.1002/for.3980090304">Disaggregation methods to expedite product line forecasting. Journal of Forecasting, 9 , 233ā254. doi:10.1002/for.3980090304</a>.<br></li> +<li><a href="https://doi.org/10.1016/S0305-0548(99)00017-9">An investigation of aggregate variable time series forecast strategies with specific subaggregate time series statistical correlation. Computers and Operations Research, 26 , 1133ā1149. doi:10.1016/S0305-0548(99)00017-9.</a><br></li> +<li><a href="https://otexts.com/fpp3/hierarchical.html">Hyndman, R.J., & Athanasopoulos, G. (2021). āForecasting: principles and practice, 3rd edition: Chapter 11: Forecasting hierarchical and grouped series.ā. OTexts: Melbourne, Australia. OTexts.com/fpp3 Accessed on July 2022.</a></li> +</ul> +</section> +<section id="optimal-reconciliation" class="level3"> +<h3 class="anchored" data-anchor-id="optimal-reconciliation">Optimal Reconciliation</h3> +<ul> +<li><a href="https://robjhyndman.com/papers/Hierarchical6.pdf">Rob J. Hyndman, Roman A. Ahmed, George Athanasopoulos, Han Lin Shang. āOptimal Combination Forecasts for Hierarchical Time Seriesā (2010).</a><br></li> +<li><a href="https://robjhyndman.com/papers/MinT.pdf">Shanika L. Wickramasuriya, George Athanasopoulos and Rob J. Hyndman. āOptimal Combination Forecasts for Hierarchical Time Seriesā (2010).</a><br></li> +<li><a href="https://doi.org/10.1145/3292500.3330976">Ben Taieb, S., & Koo, B. (2019). Regularized regression for hierarchical forecasting without unbiasedness conditions. In Proceedings of the 25th ACM SIGKDD International Conference on Knowledge Discovery & Data Mining KDD ā19 (p. 1337{1347). New York, NY, USA: Association for Computing Machinery.</a><br></li> +</ul> +</section> +<section id="hierarchical-probabilistic-coherent-predictions" class="level3"> +<h3 class="anchored" data-anchor-id="hierarchical-probabilistic-coherent-predictions">Hierarchical Probabilistic Coherent Predictions</h3> +<ul> +<li><a href="https://bridges.monash.edu/articles/thesis/Probabilistic_Forecast_Reconciliation_Theory_and_Applications/11869533">Puwasala Gamakumara Ph. D. dissertation. Monash University, Econometrics and Business Statistics. āProbabilistic Forecast Reconciliationā.</a><br></li> +<li><a href="https://proceedings.mlr.press/v70/taieb17a.html">Taieb, Souhaib Ben and Taylor, James W and Hyndman, Rob J. (2017). Coherent probabilistic forecasts for hierarchical time series. International conference on machine learning ICML.</a><br></li> +</ul> + + +</section> +</section> + +<p>If you find the code useful, please ā us on <a href="https://github.com/nixtla/hierarchicalforecast">Github</a></p></main> <!-- /main --> +<script id="quarto-html-after-body" type="application/javascript"> +window.document.addEventListener("DOMContentLoaded", function (event) { + const toggleBodyColorMode = (bsSheetEl) => { + const mode = bsSheetEl.getAttribute("data-mode"); + const bodyEl = window.document.querySelector("body"); + if (mode === "dark") { + bodyEl.classList.add("quarto-dark"); + bodyEl.classList.remove("quarto-light"); + } else { + bodyEl.classList.add("quarto-light"); + bodyEl.classList.remove("quarto-dark"); + } + } + const toggleBodyColorPrimary = () => { + const bsSheetEl = window.document.querySelector("link#quarto-bootstrap"); + if (bsSheetEl) { + toggleBodyColorMode(bsSheetEl); + } + } + toggleBodyColorPrimary(); + const icon = "ī§"; + const anchorJS = new window.AnchorJS(); + anchorJS.options = { + placement: 'right', + icon: icon + }; + anchorJS.add('.anchored'); + const isCodeAnnotation = (el) => { + for (const clz of el.classList) { + if (clz.startsWith('code-annotation-')) { + return true; + } + } + return false; + } + const clipboard = new window.ClipboardJS('.code-copy-button', { + text: function(trigger) { + const codeEl = trigger.previousElementSibling.cloneNode(true); + for (const childEl of codeEl.children) { + if (isCodeAnnotation(childEl)) { + childEl.remove(); + } + } + return codeEl.innerText; + } + }); + clipboard.on('success', function(e) { + // button target + const button = e.trigger; + // don't keep focus + button.blur(); + // flash "checked" + button.classList.add('code-copy-button-checked'); + var currentTitle = button.getAttribute("title"); + button.setAttribute("title", "Copied!"); + let tooltip; + if (window.bootstrap) { + button.setAttribute("data-bs-toggle", "tooltip"); + button.setAttribute("data-bs-placement", "left"); + button.setAttribute("data-bs-title", "Copied!"); + tooltip = new bootstrap.Tooltip(button, + { trigger: "manual", + customClass: "code-copy-button-tooltip", + offset: [0, -8]}); + tooltip.show(); + } + setTimeout(function() { + if (tooltip) { + tooltip.hide(); + button.removeAttribute("data-bs-title"); + button.removeAttribute("data-bs-toggle"); + button.removeAttribute("data-bs-placement"); + } + button.setAttribute("title", currentTitle); + button.classList.remove('code-copy-button-checked'); + }, 1000); + // clear code selection + e.clearSelection(); + }); + function tippyHover(el, contentFn) { + const config = { + allowHTML: true, + content: contentFn, + maxWidth: 500, + delay: 100, + arrow: false, + appendTo: function(el) { + return el.parentElement; + }, + interactive: true, + interactiveBorder: 10, + theme: 'quarto', + placement: 'bottom-start' + }; + window.tippy(el, config); + } + const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]'); + for (var i=0; i<noterefs.length; i++) { + const ref = noterefs[i]; + tippyHover(ref, function() { + // use id or data attribute instead here + let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href'); + try { href = new URL(href).hash; } catch {} + const id = href.replace(/^#\/?/, ""); + const note = window.document.getElementById(id); + return note.innerHTML; + }); + } + let selectedAnnoteEl; + const selectorForAnnotation = ( cell, annotation) => { + let cellAttr = 'data-code-cell="' + cell + '"'; + let lineAttr = 'data-code-annotation="' + annotation + '"'; + const selector = 'span[' + cellAttr + '][' + lineAttr + ']'; + return selector; + } + const selectCodeLines = (annoteEl) => { + const doc = window.document; + const targetCell = annoteEl.getAttribute("data-target-cell"); + const targetAnnotation = annoteEl.getAttribute("data-target-annotation"); + const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation)); + const lines = annoteSpan.getAttribute("data-code-lines").split(","); + const lineIds = lines.map((line) => { + return targetCell + "-" + line; + }) + let top = null; + let height = null; + let parent = null; + if (lineIds.length > 0) { + //compute the position of the single el (top and bottom and make a div) + const el = window.document.getElementById(lineIds[0]); + top = el.offsetTop; + height = el.offsetHeight; + parent = el.parentElement.parentElement; + if (lineIds.length > 1) { + const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]); + const bottom = lastEl.offsetTop + lastEl.offsetHeight; + height = bottom - top; + } + if (top !== null && height !== null && parent !== null) { + // cook up a div (if necessary) and position it + let div = window.document.getElementById("code-annotation-line-highlight"); + if (div === null) { + div = window.document.createElement("div"); + div.setAttribute("id", "code-annotation-line-highlight"); + div.style.position = 'absolute'; + parent.appendChild(div); + } + div.style.top = top - 2 + "px"; + div.style.height = height + 4 + "px"; + let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter"); + if (gutterDiv === null) { + gutterDiv = window.document.createElement("div"); + gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter"); + gutterDiv.style.position = 'absolute'; + const codeCell = window.document.getElementById(targetCell); + const gutter = codeCell.querySelector('.code-annotation-gutter'); + gutter.appendChild(gutterDiv); + } + gutterDiv.style.top = top - 2 + "px"; + gutterDiv.style.height = height + 4 + "px"; + } + selectedAnnoteEl = annoteEl; + } + }; + const unselectCodeLines = () => { + const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"]; + elementsIds.forEach((elId) => { + const div = window.document.getElementById(elId); + if (div) { + div.remove(); + } + }); + selectedAnnoteEl = undefined; + }; + // Attach click handler to the DT + const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); + for (const annoteDlNode of annoteDls) { + annoteDlNode.addEventListener('click', (event) => { + const clickedEl = event.target; + if (clickedEl !== selectedAnnoteEl) { + unselectCodeLines(); + const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active'); + if (activeEl) { + activeEl.classList.remove('code-annotation-active'); + } + selectCodeLines(clickedEl); + clickedEl.classList.add('code-annotation-active'); + } else { + // Unselect the line + unselectCodeLines(); + clickedEl.classList.remove('code-annotation-active'); + } + }); + } + const findCites = (el) => { + const parentEl = el.parentElement; + if (parentEl) { + const cites = parentEl.dataset.cites; + if (cites) { + return { + el, + cites: cites.split(' ') + }; + } else { + return findCites(el.parentElement) + } + } else { + return undefined; + } + }; + var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]'); + for (var i=0; i<bibliorefs.length; i++) { + const ref = bibliorefs[i]; + const citeInfo = findCites(ref); + if (citeInfo) { + tippyHover(citeInfo.el, function() { + var popup = window.document.createElement('div'); + citeInfo.cites.forEach(function(cite) { + var citeDiv = window.document.createElement('div'); + citeDiv.classList.add('hanging-indent'); + citeDiv.classList.add('csl-entry'); + var biblioDiv = window.document.getElementById('ref-' + cite); + if (biblioDiv) { + citeDiv.innerHTML = biblioDiv.innerHTML; + } + popup.appendChild(citeDiv); + }); + return popup.innerHTML; + }); + } + } +}); +</script> +</div> <!-- /content --> + + + +</body></html> \ No newline at end of file diff --git a/probabilistic_methods.html b/probabilistic_methods.html new file mode 100644 index 00000000..1c2cc138 --- /dev/null +++ b/probabilistic_methods.html @@ -0,0 +1,771 @@ +<!DOCTYPE html> +<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head> + +<meta charset="utf-8"> +<meta name="generator" content="quarto-1.3.450"> + +<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes"> + + +<title>hierarchicalforecast - Probabilistic Methods </title> +<style> +code{white-space: pre-wrap;} +span.smallcaps{font-variant: small-caps;} +div.columns{display: flex; gap: min(4vw, 1.5em);} +div.column{flex: auto; overflow-x: auto;} +div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;} +ul.task-list{list-style: none;} +ul.task-list li input[type="checkbox"] { + width: 0.8em; + margin: 0 0.8em 0.2em -1em; /* quarto-specific, see https://github.com/quarto-dev/quarto-cli/issues/4556 */ + vertical-align: middle; +} +</style> + + +<script src="site_libs/quarto-nav/quarto-nav.js"></script> +<script src="site_libs/quarto-nav/headroom.min.js"></script> +<script src="site_libs/clipboard/clipboard.min.js"></script> +<script src="site_libs/quarto-search/autocomplete.umd.js"></script> +<script src="site_libs/quarto-search/fuse.min.js"></script> +<script src="site_libs/quarto-search/quarto-search.js"></script> +<meta name="quarto:offset" content="./"> +<link href="./favicon_png.png" rel="icon" type="image/png"> +<script src="site_libs/quarto-html/quarto.js"></script> +<script src="site_libs/quarto-html/popper.min.js"></script> +<script src="site_libs/quarto-html/tippy.umd.min.js"></script> +<script src="site_libs/quarto-html/anchor.min.js"></script> +<link href="site_libs/quarto-html/tippy.css" rel="stylesheet"> +<link href="site_libs/quarto-html/quarto-syntax-highlighting.css" rel="stylesheet" id="quarto-text-highlighting-styles"> +<script src="site_libs/bootstrap/bootstrap.min.js"></script> +<link href="site_libs/bootstrap/bootstrap-icons.css" rel="stylesheet"> +<link href="site_libs/bootstrap/bootstrap.min.css" rel="stylesheet" id="quarto-bootstrap" data-mode="light"> +<script id="quarto-search-options" type="application/json">{ + "location": "navbar", + "copy-button": false, + "collapse-after": 3, + "panel-placement": "end", + "type": "overlay", + "limit": 20, + "language": { + "search-no-results-text": "No results", + "search-matching-documents-text": "matching documents", + "search-copy-link-title": "Copy link to search", + "search-hide-matches-text": "Hide additional matches", + "search-more-match-text": "more match in this document", + "search-more-matches-text": "more matches in this document", + "search-clear-button-title": "Clear", + "search-detached-cancel-button-title": "Cancel", + "search-submit-button-title": "Submit", + "search-label": "Search" + } +}</script> +<script async="" src="https://www.googletagmanager.com/gtag/js?id=G-NXJNCVR18L"></script> + +<script type="text/javascript"> + +window.dataLayer = window.dataLayer || []; +function gtag(){dataLayer.push(arguments);} +gtag('js', new Date()); +gtag('config', 'G-NXJNCVR18L', { 'anonymize_ip': true}); +</script> + + <script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script> + <script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml-full.js" type="text/javascript"></script> + +<link rel="stylesheet" href="styles.css"> +<meta property="og:title" content="hierarchicalforecast - Probabilistic Methods "> +<meta property="og:description" content=""> +<meta property="og:site-name" content="hierarchicalforecast"> +<meta name="twitter:title" content="hierarchicalforecast - Probabilistic Methods "> +<meta name="twitter:description" content=""> +<meta name="twitter:card" content="summary"> +</head> + +<body class="nav-sidebar floating nav-fixed"> + +<div id="quarto-search-results"></div> + <header id="quarto-header" class="headroom fixed-top"> + <nav class="navbar navbar-expand-lg navbar-dark "> + <div class="navbar-container container-fluid"> + <div class="navbar-brand-container"> + <a class="navbar-brand" href="./index.html"> + <span class="navbar-title">hierarchicalforecast</span> + </a> + </div> + <div id="quarto-search" class="" title="Search"></div> + <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + <span class="navbar-toggler-icon"></span> +</button> + <div class="collapse navbar-collapse" id="navbarCollapse"> + <ul class="navbar-nav navbar-nav-scroll me-auto"> + <li class="nav-item"> + <a class="nav-link active" href="./examples/tourismsmall.html" rel="" target="" aria-current="page"> + <span class="menu-text">Get Started</span></a> + </li> + <li class="nav-item dropdown "> + <a class="nav-link dropdown-toggle" href="#" id="nav-menu-nixtlaverse" role="button" data-bs-toggle="dropdown" aria-expanded="false" rel="" target=""> + <span class="menu-text">NixtlaVerse</span> + </a> + <ul class="dropdown-menu" aria-labelledby="nav-menu-nixtlaverse"> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/mlforecast" rel="" target=""> + <span class="dropdown-text">MLForecast š¤</span></a> + </li> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/neuralforecast" rel="" target=""> + <span class="dropdown-text">NeuralForecast š§ </span></a> + </li> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/statsforecast" rel="" target=""> + <span class="dropdown-text">StatsForecast ā”ļø</span></a> + </li> + </ul> + </li> + <li class="nav-item dropdown "> + <a class="nav-link dropdown-toggle" href="#" id="nav-menu-help" role="button" data-bs-toggle="dropdown" aria-expanded="false" rel="" target=""> + <span class="menu-text">Help</span> + </a> + <ul class="dropdown-menu" aria-labelledby="nav-menu-help"> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/hierarchicalforecast/issues/new/choose" rel="" target=""><i class="bi bi-bug" role="img"> +</i> + <span class="dropdown-text">Report an Issue</span></a> + </li> + <li> + <a class="dropdown-item" href="https://join.slack.com/t/nixtlacommunity/shared_invite/zt-1kd5m5db7-7OOfy0xVNf1PcvCiAPWvPw" rel="" target=""><i class="bi bi-chat-right-text" role="img"> +</i> + <span class="dropdown-text">Join our Slack</span></a> + </li> + </ul> + </li> +</ul> + <ul class="navbar-nav navbar-nav-scroll ms-auto"> + <li class="nav-item compact"> + <a class="nav-link" href="https://github.com/nixtla/hierarchicalforecast" rel="" target=""><i class="bi bi-github" role="img"> +</i> + <span class="menu-text"></span></a> + </li> + <li class="nav-item compact"> + <a class="nav-link" href="https://twitter.com/nixtlainc" rel="" target=""><i class="bi bi-twitter" role="img" aria-label="Nixtla Twitter"> +</i> + <span class="menu-text"></span></a> + </li> +</ul> + <div class="quarto-navbar-tools"> +</div> + </div> <!-- /navcollapse --> + </div> <!-- /container-fluid --> + </nav> + <nav class="quarto-secondary-nav"> + <div class="container-fluid d-flex"> + <button type="button" class="quarto-btn-toggle btn" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + <i class="bi bi-layout-text-sidebar-reverse"></i> + </button> + <nav class="quarto-page-breadcrumbs" aria-label="breadcrumb"><ol class="breadcrumb"><li class="breadcrumb-item"><a href="./core.html">API Reference</a></li><li class="breadcrumb-item"><a href="./probabilistic_methods.html"><span style="color:DarkOrange"> Probabilistic Methods </span></a></li></ol></nav> + <a class="flex-grow-1" role="button" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + </a> + </div> + </nav> +</header> +<!-- content --> +<div id="quarto-content" class="quarto-container page-columns page-rows-contents page-layout-article page-navbar"> +<!-- sidebar --> + <nav id="quarto-sidebar" class="sidebar collapse collapse-horizontal sidebar-navigation floating overflow-auto"> + <div class="sidebar-menu-container"> + <ul class="list-unstyled mt-1"> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./index.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Hierarchical Forecast š</span></a> + </div> +</li> + <li class="px-0"><hr class="sidebar-divider hi "></li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-1" aria-expanded="false"> + <span class="menu-text">Getting Started</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-1" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-1" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/installation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Install</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/tourismsmall.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Reconciliation Quick Start</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/introduction.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Introduction</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-2" aria-expanded="false"> + <span class="menu-text">Tutorials</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-2" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-2" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-3" aria-expanded="false"> + <span class="menu-text">Point Reconciliation</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-3" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-3" class="collapse list-unstyled sidebar-section depth2 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/australiandomestictourism.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Geographical Aggregation (Tourism)</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/australianprisonpopulation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Geographical Aggregation (Prison Population)</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/nonnegativereconciliation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Non-Negative MinTrace</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-4" aria-expanded="false"> + <span class="menu-text">Probabilistic Reconciliation</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-4" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-4" class="collapse list-unstyled sidebar-section depth2 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/australiandomestictourism-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Normality</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/australiandomestictourism-bootstraped-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Bootstrap</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/australiandomestictourism-permbu-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">PERMBU</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/tourismlarge-evaluation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Probabilistic Forecast Evaluation</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-5" aria-expanded="false"> + <span class="menu-text">ML Forecast Reconciliation</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-5" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-5" class="collapse list-unstyled sidebar-section depth2 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/hierarchicalforecast-gluonts.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">GluonTS</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/mlframeworksexample.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Neural/MLForecast</span></a> + </div> +</li> + </ul> + </li> + </ul> + </li> + <li class="sidebar-item"> + <span class="menu-text">Methods</span> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-6" aria-expanded="true"> + <span class="menu-text">API Reference</span></a> + <a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-6" aria-expanded="true" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-6" class="collapse list-unstyled sidebar-section depth1 show"> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./core.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Core </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./methods.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Reconciliation Methods </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./probabilistic_methods.html" class="sidebar-item-text sidebar-link active"> + <span class="menu-text"><span style="color:DarkOrange"> Probabilistic Methods </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./evaluation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Hierarchical Evaluation</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./utils.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Aggregation/Visualization Utils</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-7" aria-expanded="false"> + <span class="menu-text">Community</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-7" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-7" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item"> + <span class="menu-text">Contributing</span> + </li> + </ul> + </li> + </ul> + </div> +</nav> +<div id="quarto-sidebar-glass" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass"></div> +<!-- margin-sidebar --> + <div id="quarto-margin-sidebar" class="sidebar margin-sidebar"> + <nav id="TOC" role="doc-toc" class="toc-active"> + <h2 id="toc-title">On this page</h2> + + <ul> + <li><a href="#normality" id="toc-normality" class="nav-link active" data-scroll-target="#normality"><span style="color:DarkBlue"> 1. Normality </span></a> + <ul class="collapse"> + <li><a href="#normality-1" id="toc-normality-1" class="nav-link" data-scroll-target="#normality-1">Normality</a></li> + <li><a href="#normality.get_samples" id="toc-normality.get_samples" class="nav-link" data-scroll-target="#normality.get_samples">Normality.get_samples</a></li> + </ul></li> + <li><a href="#bootstrap" id="toc-bootstrap" class="nav-link" data-scroll-target="#bootstrap"><span style="color:DarkBlue"> 2. Bootstrap </span></a> + <ul class="collapse"> + <li><a href="#bootstrap-1" id="toc-bootstrap-1" class="nav-link" data-scroll-target="#bootstrap-1">Bootstrap</a></li> + <li><a href="#bootstrap.get_samples" id="toc-bootstrap.get_samples" class="nav-link" data-scroll-target="#bootstrap.get_samples">Bootstrap.get_samples</a></li> + </ul></li> + <li><a href="#permbu" id="toc-permbu" class="nav-link" data-scroll-target="#permbu"><span style="color:DarkBlue"> 3. PERMBU </span></a> + <ul class="collapse"> + <li><a href="#permbu-1" id="toc-permbu-1" class="nav-link" data-scroll-target="#permbu-1">PERMBU</a></li> + <li><a href="#permbu.get_samples" id="toc-permbu.get_samples" class="nav-link" data-scroll-target="#permbu.get_samples">PERMBU.get_samples</a></li> + </ul></li> + <li><a href="#references" id="toc-references" class="nav-link" data-scroll-target="#references"><span style="color:DarkBlue"> References </span></a></li> + </ul> +<div class="toc-actions"><div><i class="bi bi-github"></i></div><div class="action-links"><p><a href="https://github.com/Nixtla/hierarchicalforecast/issues/new" class="toc-action">Report an issue</a></p></div></div></nav> + </div> +<!-- main --> +<main class="content" id="quarto-document-content"> + +<header id="title-block-header" class="quarto-title-block default"> +<div class="quarto-title"> +<h1 class="title"><span style="color:DarkOrange"> Probabilistic Methods </span></h1> +</div> + + + +<div class="quarto-title-meta"> + + + + + </div> + + +</header> + +<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! --> +<p>Here we provide a collection of methods designed to provide hierarchically coherent probabilistic distributions, which means that they generate samples of multivariate time series with hierarchical linear constraints.</p> +<p>We designed these methods to extend the <code>core.HierarchicalForecast</code> capabilities class. Check their <a href="https://nixtla.github.io/hierarchicalforecast/examples/example.html">usage example here</a>.</p> +<section id="normality" class="level1"> +<h1><span style="color:DarkBlue"> 1. Normality </span></h1> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/probabilistic_methods.py#L17" target="_blank" style="float:right; font-size:smaller">source</a></p> +<section id="normality-1" class="level3"> +<h3 class="anchored" data-anchor-id="normality-1">Normality</h3> +<blockquote class="blockquote"> +<pre><code> Normality (S:numpy.ndarray, P:numpy.ndarray, y_hat:numpy.ndarray, + sigmah:numpy.ndarray, W:numpy.ndarray, seed:int=0)</code></pre> +</blockquote> +<p>Normality Probabilistic Reconciliation Class.</p> +<p>The Normality method leverages the Gaussian Distribution linearity, to generate hierarchically coherent prediction distributions. This class is meant to be used as the <code>sampler</code> input as other <code>HierarchicalForecast</code> <a href="https://nixtla.github.io/hierarchicalforecast/methods.html">reconciliation classes</a>.</p> +<p>Given base forecasts under a normal distribution: <span class="math display">\[\hat{y}_{h} \sim \mathrm{N}(\hat{\boldsymbol{\mu}}, \hat{\mathbf{W}}_{h})\]</span></p> +<p>The reconciled forecasts are also normally distributed: <span class="math display">\[\tilde{y}_{h} \sim \mathrm{N}(\mathbf{S}\mathbf{P}\hat{\boldsymbol{\mu}}, +\mathbf{S}\mathbf{P}\hat{\mathbf{W}}_{h} \mathbf{P}^{\intercal} \mathbf{S}^{\intercal})\]</span></p> +<p><strong>Parameters:</strong><br> <code>S</code>: np.array, summing matrix of size (<code>base</code>, <code>bottom</code>).<br> <code>P</code>: np.array, reconciliation matrix of size (<code>bottom</code>, <code>base</code>).<br> <code>y_hat</code>: Point forecasts values of size (<code>base</code>, <code>horizon</code>).<br> <code>W</code>: np.array, hierarchical covariance matrix of size (<code>base</code>, <code>base</code>).<br> <code>sigmah</code>: np.array, forecast standard dev. of size (<code>base</code>, <code>horizon</code>).<br> <code>num_samples</code>: int, number of bootstraped samples generated.<br> <code>seed</code>: int, random seed for numpy generatorās replicability.<br></p> +<p><strong>References:</strong><br> - <a href="https://www.sciencedirect.com/science/article/pii/S0377221722006087">Panagiotelis A., Gamakumara P. Athanasopoulos G., and Hyndman R. J. (2022). āProbabilistic forecast reconciliation: Properties, evaluation and score optimisationā. European Journal of Operational Research.</a></p> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/probabilistic_methods.py#L68" target="_blank" style="float:right; font-size:smaller">source</a></p> +</section> +<section id="normality.get_samples" class="level3"> +<h3 class="anchored" data-anchor-id="normality.get_samples">Normality.get_samples</h3> +<blockquote class="blockquote"> +<pre><code> Normality.get_samples (num_samples:int=None)</code></pre> +</blockquote> +<p>Normality Coherent Samples.</p> +<p>Obtains coherent samples under the Normality assumptions.</p> +<p><strong>Parameters:</strong><br> <code>num_samples</code>: int, number of samples generated from coherent distribution.<br></p> +<p><strong>Returns:</strong><br> <code>samples</code>: Coherent samples of size (<code>base</code>, <code>horizon</code>, <code>num_samples</code>).</p> +</section> +</section> +<section id="bootstrap" class="level1"> +<h1><span style="color:DarkBlue"> 2. Bootstrap </span></h1> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/probabilistic_methods.py#L113" target="_blank" style="float:right; font-size:smaller">source</a></p> +<section id="bootstrap-1" class="level3"> +<h3 class="anchored" data-anchor-id="bootstrap-1">Bootstrap</h3> +<blockquote class="blockquote"> +<pre><code> Bootstrap (S:numpy.ndarray, P:numpy.ndarray, y_hat:numpy.ndarray, + y_insample:numpy.ndarray, y_hat_insample:numpy.ndarray, + num_samples:int=100, seed:int=0, W:numpy.ndarray=None)</code></pre> +</blockquote> +<p>Bootstrap Probabilistic Reconciliation Class.</p> +<p>This method goes beyond the normality assumption for the base forecasts, the technique simulates future sample paths and uses them to generate base sample paths that are latered reconciled. This clever idea and its simplicity allows to generate coherent bootstraped prediction intervals for any reconciliation strategy. This class is meant to be used as the <code>sampler</code> input as other <code>HierarchicalForecast</code> <a href="https://nixtla.github.io/hierarchicalforecast/methods.html">reconciliation classes</a>.</p> +<p>Given a boostraped set of simulated sample paths: <span class="math display">\[(\hat{\mathbf{y}}^{[1]}_{\tau}, \dots ,\hat{\mathbf{y}}^{[B]}_{\tau})\]</span></p> +<p>The reconciled sample paths allow for reconciled distributional forecasts: <span class="math display">\[(\mathbf{S}\mathbf{P}\hat{\mathbf{y}}^{[1]}_{\tau}, \dots ,\mathbf{S}\mathbf{P}\hat{\mathbf{y}}^{[B]}_{\tau})\]</span></p> +<p><strong>Parameters:</strong><br> <code>S</code>: np.array, summing matrix of size (<code>base</code>, <code>bottom</code>).<br> <code>P</code>: np.array, reconciliation matrix of size (<code>bottom</code>, <code>base</code>).<br> <code>y_hat</code>: Point forecasts values of size (<code>base</code>, <code>horizon</code>).<br> <code>y_insample</code>: Insample values of size (<code>base</code>, <code>insample_size</code>).<br> <code>y_hat_insample</code>: Insample point forecasts of size (<code>base</code>, <code>insample_size</code>).<br> <code>num_samples</code>: int, number of bootstraped samples generated.<br> <code>seed</code>: int, random seed for numpy generatorās replicability.<br></p> +<p><strong>References:</strong><br> - <a href="https://bridges.monash.edu/articles/thesis/Probabilistic_Forecast_Reconciliation_Theory_and_Applications/11869533">Puwasala Gamakumara Ph. D. dissertation. Monash University, Econometrics and Business Statistics (2020). āProbabilistic Forecast Reconciliationā</a> - <a href="https://www.sciencedirect.com/science/article/pii/S0377221722006087">Panagiotelis A., Gamakumara P. Athanasopoulos G., and Hyndman R. J. (2022). āProbabilistic forecast reconciliation: Properties, evaluation and score optimisationā. European Journal of Operational Research.</a></p> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/probabilistic_methods.py#L162" target="_blank" style="float:right; font-size:smaller">source</a></p> +</section> +<section id="bootstrap.get_samples" class="level3"> +<h3 class="anchored" data-anchor-id="bootstrap.get_samples">Bootstrap.get_samples</h3> +<blockquote class="blockquote"> +<pre><code> Bootstrap.get_samples (num_samples:int=None)</code></pre> +</blockquote> +<p>Bootstrap Sample Reconciliation Method.</p> +<p>Applies Bootstrap sample reconciliation method as defined by Gamakumara 2020. Generating independent sample paths and reconciling them with Bootstrap.</p> +<p><strong>Parameters:</strong><br> <code>num_samples</code>: int, number of samples generated from coherent distribution.<br></p> +<p><strong>Returns:</strong><br> <code>samples</code>: Coherent samples of size (<code>base</code>, <code>horizon</code>, <code>num_samples</code>).</p> +</section> +</section> +<section id="permbu" class="level1"> +<h1><span style="color:DarkBlue"> 3. PERMBU </span></h1> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/probabilistic_methods.py#L212" target="_blank" style="float:right; font-size:smaller">source</a></p> +<section id="permbu-1" class="level3"> +<h3 class="anchored" data-anchor-id="permbu-1">PERMBU</h3> +<blockquote class="blockquote"> +<pre><code> PERMBU (S:numpy.ndarray, tags:Dict[str,numpy.ndarray], + y_hat:numpy.ndarray, y_insample:numpy.ndarray, + y_hat_insample:numpy.ndarray, sigmah:numpy.ndarray, + num_samples:int=None, seed:int=0, P:numpy.ndarray=None)</code></pre> +</blockquote> +<p>PERMBU Probabilistic Reconciliation Class.</p> +<p>The PERMBU method leverages empirical bottom-level marginal distributions with empirical copula functions (describing bottom-level dependencies) to generate the distribution of aggregate-level distributions using BottomUp reconciliation. The sample reordering technique in the PERMBU method reinjects multivariate dependencies into independent bottom-level samples.</p> +<pre><code>Algorithm: +1. For all series compute conditional marginals distributions. +2. Compute residuals $\hat{\epsilon}_{i,t}$ and obtain rank permutations. +2. Obtain K-sample from the bottom-level series predictions. +3. Apply recursively through the hierarchical structure:<br> + 3.1. For a given aggregate series $i$ and its children series:<br> + 3.2. Obtain children's empirical joint using sample reordering copula.<br> + 3.2. From the children's joint obtain the aggregate series's samples. </code></pre> +<p><strong>Parameters:</strong><br> <code>S</code>: np.array, summing matrix of size (<code>base</code>, <code>bottom</code>).<br> <code>tags</code>: Each key is a level and each value its <code>S</code> indices.<br> <code>y_insample</code>: Insample values of size (<code>base</code>, <code>insample_size</code>).<br> <code>y_hat_insample</code>: Insample point forecasts of size (<code>base</code>, <code>insample_size</code>).<br> <code>sigmah</code>: np.array, forecast standard dev. of size (<code>base</code>, <code>horizon</code>).<br> <code>num_samples</code>: int, number of normal prediction samples generated.<br> <code>seed</code>: int, random seed for numpy generatorās replicability.<br></p> +<p><strong>References:</strong><br> - <a href="https://proceedings.mlr.press/v70/taieb17a.html">Taieb, Souhaib Ben and Taylor, James W and Hyndman, Rob J. (2017). Coherent probabilistic forecasts for hierarchical time series. International conference on machine learning ICML.</a></p> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/probabilistic_methods.py#L339" target="_blank" style="float:right; font-size:smaller">source</a></p> +</section> +<section id="permbu.get_samples" class="level3"> +<h3 class="anchored" data-anchor-id="permbu.get_samples">PERMBU.get_samples</h3> +<blockquote class="blockquote"> +<pre><code> PERMBU.get_samples (num_samples:int=None)</code></pre> +</blockquote> +<p>PERMBU Sample Reconciliation Method.</p> +<p>Applies PERMBU reconciliation method as defined by Taieb et. al 2017. Generating independent base prediction samples, restoring its multivariate dependence using estimated copula with reordering and applying the BottomUp aggregation to the new samples.</p> +<p><strong>Parameters:</strong><br> <code>num_samples</code>: int, number of samples generated from coherent distribution.<br></p> +<p><strong>Returns:</strong><br> <code>samples</code>: Coherent samples of size (<code>base</code>, <code>horizon</code>, <code>num_samples</code>).</p> +</section> +</section> +<section id="references" class="level1"> +<h1><span style="color:DarkBlue"> References </span></h1> +<ul> +<li><a href="https://otexts.com/fpp3/rec-prob.html">Rob J. Hyndman and George Athanasopoulos (2018). āForecasting principles and practice, Reconciled distributional forecastsā.</a><br></li> +<li><a href="https://bridges.monash.edu/articles/thesis/Probabilistic_Forecast_Reconciliation_Theory_and_Applications/11869533">Puwasala Gamakumara Ph. D. dissertation. Monash University, Econometrics and Business Statistics (2020). āProbabilistic Forecast Reconciliationā</a><br></li> +<li><a href="https://www.sciencedirect.com/science/article/pii/S0377221722006087">Panagiotelis A., Gamakumara P. Athanasopoulos G., and Hyndman R. J. (2022). āProbabilistic forecast reconciliation: Properties, evaluation and score optimisationā. European Journal of Operational Research.</a><br></li> +<li><a href="https://proceedings.mlr.press/v70/taieb17a.html">Taieb, Souhaib Ben and Taylor, James W and Hyndman, Rob J. (2017). Coherent probabilistic forecasts for hierarchical time series. International conference on machine learning ICML.</a><br></li> +</ul> + + +</section> + +<p>If you find the code useful, please ā us on <a href="https://github.com/nixtla/hierarchicalforecast">Github</a></p></main> <!-- /main --> +<script id="quarto-html-after-body" type="application/javascript"> +window.document.addEventListener("DOMContentLoaded", function (event) { + const toggleBodyColorMode = (bsSheetEl) => { + const mode = bsSheetEl.getAttribute("data-mode"); + const bodyEl = window.document.querySelector("body"); + if (mode === "dark") { + bodyEl.classList.add("quarto-dark"); + bodyEl.classList.remove("quarto-light"); + } else { + bodyEl.classList.add("quarto-light"); + bodyEl.classList.remove("quarto-dark"); + } + } + const toggleBodyColorPrimary = () => { + const bsSheetEl = window.document.querySelector("link#quarto-bootstrap"); + if (bsSheetEl) { + toggleBodyColorMode(bsSheetEl); + } + } + toggleBodyColorPrimary(); + const icon = "ī§"; + const anchorJS = new window.AnchorJS(); + anchorJS.options = { + placement: 'right', + icon: icon + }; + anchorJS.add('.anchored'); + const isCodeAnnotation = (el) => { + for (const clz of el.classList) { + if (clz.startsWith('code-annotation-')) { + return true; + } + } + return false; + } + const clipboard = new window.ClipboardJS('.code-copy-button', { + text: function(trigger) { + const codeEl = trigger.previousElementSibling.cloneNode(true); + for (const childEl of codeEl.children) { + if (isCodeAnnotation(childEl)) { + childEl.remove(); + } + } + return codeEl.innerText; + } + }); + clipboard.on('success', function(e) { + // button target + const button = e.trigger; + // don't keep focus + button.blur(); + // flash "checked" + button.classList.add('code-copy-button-checked'); + var currentTitle = button.getAttribute("title"); + button.setAttribute("title", "Copied!"); + let tooltip; + if (window.bootstrap) { + button.setAttribute("data-bs-toggle", "tooltip"); + button.setAttribute("data-bs-placement", "left"); + button.setAttribute("data-bs-title", "Copied!"); + tooltip = new bootstrap.Tooltip(button, + { trigger: "manual", + customClass: "code-copy-button-tooltip", + offset: [0, -8]}); + tooltip.show(); + } + setTimeout(function() { + if (tooltip) { + tooltip.hide(); + button.removeAttribute("data-bs-title"); + button.removeAttribute("data-bs-toggle"); + button.removeAttribute("data-bs-placement"); + } + button.setAttribute("title", currentTitle); + button.classList.remove('code-copy-button-checked'); + }, 1000); + // clear code selection + e.clearSelection(); + }); + function tippyHover(el, contentFn) { + const config = { + allowHTML: true, + content: contentFn, + maxWidth: 500, + delay: 100, + arrow: false, + appendTo: function(el) { + return el.parentElement; + }, + interactive: true, + interactiveBorder: 10, + theme: 'quarto', + placement: 'bottom-start' + }; + window.tippy(el, config); + } + const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]'); + for (var i=0; i<noterefs.length; i++) { + const ref = noterefs[i]; + tippyHover(ref, function() { + // use id or data attribute instead here + let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href'); + try { href = new URL(href).hash; } catch {} + const id = href.replace(/^#\/?/, ""); + const note = window.document.getElementById(id); + return note.innerHTML; + }); + } + let selectedAnnoteEl; + const selectorForAnnotation = ( cell, annotation) => { + let cellAttr = 'data-code-cell="' + cell + '"'; + let lineAttr = 'data-code-annotation="' + annotation + '"'; + const selector = 'span[' + cellAttr + '][' + lineAttr + ']'; + return selector; + } + const selectCodeLines = (annoteEl) => { + const doc = window.document; + const targetCell = annoteEl.getAttribute("data-target-cell"); + const targetAnnotation = annoteEl.getAttribute("data-target-annotation"); + const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation)); + const lines = annoteSpan.getAttribute("data-code-lines").split(","); + const lineIds = lines.map((line) => { + return targetCell + "-" + line; + }) + let top = null; + let height = null; + let parent = null; + if (lineIds.length > 0) { + //compute the position of the single el (top and bottom and make a div) + const el = window.document.getElementById(lineIds[0]); + top = el.offsetTop; + height = el.offsetHeight; + parent = el.parentElement.parentElement; + if (lineIds.length > 1) { + const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]); + const bottom = lastEl.offsetTop + lastEl.offsetHeight; + height = bottom - top; + } + if (top !== null && height !== null && parent !== null) { + // cook up a div (if necessary) and position it + let div = window.document.getElementById("code-annotation-line-highlight"); + if (div === null) { + div = window.document.createElement("div"); + div.setAttribute("id", "code-annotation-line-highlight"); + div.style.position = 'absolute'; + parent.appendChild(div); + } + div.style.top = top - 2 + "px"; + div.style.height = height + 4 + "px"; + let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter"); + if (gutterDiv === null) { + gutterDiv = window.document.createElement("div"); + gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter"); + gutterDiv.style.position = 'absolute'; + const codeCell = window.document.getElementById(targetCell); + const gutter = codeCell.querySelector('.code-annotation-gutter'); + gutter.appendChild(gutterDiv); + } + gutterDiv.style.top = top - 2 + "px"; + gutterDiv.style.height = height + 4 + "px"; + } + selectedAnnoteEl = annoteEl; + } + }; + const unselectCodeLines = () => { + const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"]; + elementsIds.forEach((elId) => { + const div = window.document.getElementById(elId); + if (div) { + div.remove(); + } + }); + selectedAnnoteEl = undefined; + }; + // Attach click handler to the DT + const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); + for (const annoteDlNode of annoteDls) { + annoteDlNode.addEventListener('click', (event) => { + const clickedEl = event.target; + if (clickedEl !== selectedAnnoteEl) { + unselectCodeLines(); + const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active'); + if (activeEl) { + activeEl.classList.remove('code-annotation-active'); + } + selectCodeLines(clickedEl); + clickedEl.classList.add('code-annotation-active'); + } else { + // Unselect the line + unselectCodeLines(); + clickedEl.classList.remove('code-annotation-active'); + } + }); + } + const findCites = (el) => { + const parentEl = el.parentElement; + if (parentEl) { + const cites = parentEl.dataset.cites; + if (cites) { + return { + el, + cites: cites.split(' ') + }; + } else { + return findCites(el.parentElement) + } + } else { + return undefined; + } + }; + var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]'); + for (var i=0; i<bibliorefs.length; i++) { + const ref = bibliorefs[i]; + const citeInfo = findCites(ref); + if (citeInfo) { + tippyHover(citeInfo.el, function() { + var popup = window.document.createElement('div'); + citeInfo.cites.forEach(function(cite) { + var citeDiv = window.document.createElement('div'); + citeDiv.classList.add('hanging-indent'); + citeDiv.classList.add('csl-entry'); + var biblioDiv = window.document.getElementById('ref-' + cite); + if (biblioDiv) { + citeDiv.innerHTML = biblioDiv.innerHTML; + } + popup.appendChild(citeDiv); + }); + return popup.innerHTML; + }); + } + } +}); +</script> +</div> <!-- /content --> + + + +</body></html> \ No newline at end of file diff --git a/robots.txt b/robots.txt new file mode 100644 index 00000000..ea76c916 --- /dev/null +++ b/robots.txt @@ -0,0 +1 @@ +Sitemap: https://Nixtla.github.io/hierarchicalforecast/sitemap.xml diff --git a/search.json b/search.json new file mode 100644 index 00000000..e7f5c9f9 --- /dev/null +++ b/search.json @@ -0,0 +1,541 @@ +[ + { + "objectID": "utils.html", + "href": "utils.html", + "title": "Aggregation/Visualization Utils", + "section": "", + "text": "The HierarchicalForecast package contains utility functions to wrangle and visualize hierarchical series datasets. The aggregate function of the module allows you to create a hierarchy from categorical variables representing the structure levels, returning also the aggregation contraints matrix \\(\\mathbf{S}\\).\nIn addition, HierarchicalForecast ensures compatibility of its reconciliation methods with other popular machine-learning libraries via its external forecast adapters that transform output base forecasts from external libraries into a compatible data frame format.\n\n Aggregate Function \n\nsource\n\naggregate\n\n aggregate (df:pandas.core.frame.DataFrame, spec:List[List[str]],\n is_balanced:bool=False, sparse_s:bool=False)\n\nUtils Aggregation Function. Aggregates bottom level series contained in the pandas DataFrame df according to levels defined in the spec list.\n\n\n\n\n\n\n\n\n\n\nType\nDefault\nDetails\n\n\n\n\ndf\nDataFrame\n\nDataframe with columns ['ds', 'y'] and columns to aggregate.\n\n\nspec\ntyping.List[typing.List[str]]\n\nList of levels. Each element of the list should contain a list of columns of df to aggregate.\n\n\nis_balanced\nbool\nFalse\nDeprecated.\n\n\nsparse_s\nbool\nFalse\nReturn S_df as a sparse dataframe.\n\n\nReturns\npandas DataFrame\n\nHierarchically structured series.\n\n\n\n\n\n\n Hierarchical Visualization \n\nsource\n\nHierarchicalPlot\n\n HierarchicalPlot (S:pandas.core.frame.DataFrame,\n tags:Dict[str,numpy.ndarray])\n\nHierarchical Plot\nThis class contains a collection of matplotlib visualization methods, suited for small to medium sized hierarchical series.\nParameters: S: pd.DataFrame with summing matrix of size (base, bottom), see aggregate function. tags: np.ndarray, with hierarchical aggregation indexes, where each key is a level and its value contains tags associated to that level.\n\nsource\n\n\nplot_summing_matrix\n\n plot_summing_matrix ()\n\nSummation Constraints plot\nThis method simply plots the hierarchical aggregation constraints matrix \\(\\mathbf{S}\\).\n\nsource\n\n\nplot_series\n\n plot_series (series:str, Y_df:Optional[pandas.core.frame.DataFrame]=None,\n models:Optional[List[str]]=None,\n level:Optional[List[int]]=None)\n\nSingle Series plot\nParameters: series: str, string identifying the 'unique_id' any-level series to plot. Y_df: pd.DataFrame, hierarchically structured series (\\(\\mathbf{y}_{[a,b]}\\)). It contains columns ['unique_id', 'ds', 'y'], it may have 'models'. models: List[str], string identifying filtering model columns. level: float list 0-100, confidence levels for prediction intervals available in Y_df.\nReturns: Single series plot with filtered models and prediction interval level.\n\nsource\n\n\nplot_hierarchically_linked_series\n\n plot_hierarchically_linked_series (bottom_series:str,\n Y_df:Optional[pandas.core.frame.DataFr\n ame]=None,\n models:Optional[List[str]]=None,\n level:Optional[List[int]]=None)\n\nHierarchically Linked Series plot\nParameters: bottom_series: str, string identifying the 'unique_id' bottom-level series to plot. Y_df: pd.DataFrame, hierarchically structured series (\\(\\mathbf{y}_{[a,b]}\\)). It contains columns [āunique_idā, ādsā, āyā] and models. models: List[str], string identifying filtering model columns. level: float list 0-100, confidence levels for prediction intervals available in Y_df.\nReturns: Collection of hierarchilly linked series plots associated with the bottom_series and filtered models and prediction interval level.\n\nsource\n\n\nplot_hierarchical_predictions_gap\n\n plot_hierarchical_predictions_gap (Y_df:pandas.core.frame.DataFrame,\n models:Optional[List[str]]=None,\n xlabel:Optional=None,\n ylabel:Optional=None)\n\nHierarchically Predictions Gap plot\nParameters: Y_df: pd.DataFrame, hierarchically structured series (\\(\\mathbf{y}_{[a,b]}\\)). It contains columns [āunique_idā, ādsā, āyā] and models. models: List[str], string identifying filtering model columns. xlabel: str, string for the plotās x axis label. ylable: str, string for the plotās y axis label.\nReturns: Plots of aggregated predictions at different levels of the hierarchical structure. The aggregation is performed according to the tag levels see aggregate function.\n\nfrom statsforecast.core import StatsForecast\nfrom statsforecast.models import AutoARIMA, ETS, Naive\nfrom datasetsforecast.hierarchical import HierarchicalData\n\nY_df, S, tags = HierarchicalData.load('./data', 'Labour')\nY_df['ds'] = pd.to_datetime(Y_df['ds'])\n\nY_test_df = Y_df.groupby('unique_id').tail(24)\nY_train_df = Y_df.drop(Y_test_df.index)\nY_test_df = Y_test_df.set_index('unique_id')\nY_train_df = Y_train_df.set_index('unique_id')\n\nfcst = StatsForecast(\n df=Y_train_df, \n #models=[AutoARIMA(season_length=12), Naive()], \n models=[ETS(season_length=12, model='AAZ')],\n freq='MS', \n n_jobs=-1\n)\nY_hat_df = fcst.forecast(h=24)\n\n# Plot prediction difference of different aggregation\n# Levels Country, Country/Region, Country/Gender/Region ...\nhplots = HierarchicalPlot(S=S, tags=tags)\n\nhplots.plot_hierarchical_predictions_gap(\n Y_df=Y_hat_df, models='ETS',\n xlabel='Month', ylabel='Predictions',\n)\n\n\n\n\n External Forecast Adapters \n\nsource\n\nsamples_to_quantiles_df\n\n samples_to_quantiles_df (samples:numpy.ndarray, unique_ids:Iterable[str],\n dates:Iterable,\n quantiles:Optional[Iterable[float]]=None,\n level:Optional[Iterable[int]]=None,\n model_name:Optional[str]='model')\n\nTransform Random Samples into HierarchicalForecast input. Auxiliary function to create compatible HierarchicalForecast input Y_hat_df dataframe.\nParameters: samples: numpy array. Samples from forecast distribution of shape [n_series, n_samples, horizon]. unique_ids: string list. Unique identifiers for each time series. dates: datetime list. List of forecast dates. quantiles: float list in [0., 1.]. Alternative to level, quantiles to estimate from y distribution. level: int list in [0,100]. Probability levels for prediction intervals. model_name: string. Name of forecasting model.\nReturns: quantiles: float list in [0., 1.]. quantiles to estimate from y distribution . Y_hat_df: pd.DataFrame. With base quantile forecasts with columns ds and models to reconcile indexed by unique_id.\n\n\n\n\n\nIf you find the code useful, please ā us on Github" + }, + { + "objectID": "evaluation.html", + "href": "evaluation.html", + "title": "Hierarchical Evaluation", + "section": "", + "text": "To assist the evaluation of hierarchical forecasting systems, we make available accuracy metrics along with the HierarchicalEvaluation module that facilitates the measurement of predictionās accuracy through the hierarchy levels.\nThe available metrics include point and probabilistic multivariate scoring rules that were used in previous hierarchical forecasting studies.\nIf you find the code useful, please ā us on Github" + }, + { + "objectID": "evaluation.html#relative-mean-squared-error", + "href": "evaluation.html#relative-mean-squared-error", + "title": "Hierarchical Evaluation", + "section": "Relative Mean Squared Error", + "text": "Relative Mean Squared Error\n\nsource\n\nrel_mse\n\n rel_mse (y, y_hat, y_train, mask=None)\n\nRelative Mean Squared Error\nComputes Relative mean squared error (RelMSE), as proposed by Hyndman & Koehler (2006) as an alternative to percentage errors, to avoid measure unstability.\n\\[ \\mathrm{RelMSE}(\\mathbf{y}, \\mathbf{\\hat{y}}, \\mathbf{\\hat{y}}^{naive1}) =\n\\frac{\\mathrm{MSE}(\\mathbf{y}, \\mathbf{\\hat{y}})}{\\mathrm{MSE}(\\mathbf{y}, \\mathbf{\\hat{y}}^{naive1})} \\]\nParameters: y: numpy array, Actual values of size (n_series, horizon). y_hat: numpy array, Predicted values (n_series, horizon). mask: numpy array, Specifies date stamps per serie to consider in loss.\nReturns: loss: float.\nReferences: - Hyndman, R. J and Koehler, A. B. (2006). āAnother look at measures of forecast accuracyā, International Journal of Forecasting, Volume 22, Issue 4. - Kin G. Olivares, O. Nganba Meetei, Ruijun Ma, Rohan Reddy, Mengfei Cao, Lee Dicker. āProbabilistic Hierarchical Forecasting with Deep Poisson Mixtures. Submitted to the International Journal Forecasting, Working paper available at arxiv." + }, + { + "objectID": "evaluation.html#mean-squared-scaled-error", + "href": "evaluation.html#mean-squared-scaled-error", + "title": "Hierarchical Evaluation", + "section": "Mean Squared Scaled Error", + "text": "Mean Squared Scaled Error\n\nsource\n\nmsse\n\n msse (y, y_hat, y_train, mask=None)\n\nMean Squared Scaled Error\nComputes Mean squared scaled error (MSSE), as proposed by Hyndman & Koehler (2006) as an alternative to percentage errors, to avoid measure unstability.\n\\[ \\mathrm{MSSE}(\\mathbf{y}, \\mathbf{\\hat{y}}, \\mathbf{y}^{in-sample}) =\n\\frac{\\frac{1}{h} \\sum^{t+h}_{\\tau=t+1} (y_{\\tau} - \\hat{y}_{\\tau})^2}{\\frac{1}{t-1} \\sum^{t}_{\\tau=2} (y_{\\tau} - y_{\\tau-1})^2},\\]\nwhere \\(n\\) (\\(n=\\)n) is the size of the training data, and \\(h\\) is the forecasting horizon (\\(h=\\)horizon).\nParameters: y: numpy array, Actual values of size (n_series, horizon). y_hat: numpy array, Predicted values (n_series, horizon). y_train: numpy array, Predicted values (n_series, n). mask: numpy array, Specifies date stamps per serie to consider in loss.\nReturns: loss: float.\nReferences: - Hyndman, R. J and Koehler, A. B. (2006). āAnother look at measures of forecast accuracyā, International Journal of Forecasting, Volume 22, Issue 4." + }, + { + "objectID": "evaluation.html#scaled-crps", + "href": "evaluation.html#scaled-crps", + "title": "Hierarchical Evaluation", + "section": "Scaled CRPS", + "text": "Scaled CRPS\n\nsource\n\nscaled_crps\n\n scaled_crps (y, y_hat, quantiles)\n\nScaled Continues Ranked Probability Score\nCalculates a scaled variation of the CRPS, as proposed by Rangapuram (2021), to measure the accuracy of predicted quantiles y_hat compared to the observation y.\nThis metric averages percentual weighted absolute deviations as defined by the quantile losses.\n\\[ \\mathrm{sCRPS}(\\hat{F}_{\\tau}, \\mathbf{y}_{\\tau}) = \\frac{2}{N} \\sum_{i}\n\\int^{1}_{0}\n\\frac{\\mathrm{QL}(\\hat{F}_{i,\\tau}, y_{i,\\tau})_{q}}{\\sum_{i} | y_{i,\\tau} |} dq \\]\nwhere \\(\\hat{F}_{\\tau}\\) is the an estimated multivariate distribution, and \\(y_{i,\\tau}\\) are its realizations.\nParameters: y: numpy array, Actual values of size (n_series, horizon). y_hat: numpy array, Predicted quantiles of size (n_series, horizon, n_quantiles). quantiles: numpy array,(n_quantiles). Quantiles to estimate from the distribution of y.\nReturns: loss: float.\nReferences: - Gneiting, Tilmann. (2011). āQuantiles as optimal point forecastsā. International Journal of Forecasting. - Spyros Makridakis, Evangelos Spiliotis, Vassilios Assimakopoulos, Zhi Chen, Anil Gaba, Ilia Tsetlin, Robert L. Winkler. (2022). āThe M5 uncertainty competition: Results, findings and conclusionsā. International Journal of Forecasting. - Syama Sundar Rangapuram, Lucien D Werner, Konstantinos Benidis, Pedro Mercado, Jan Gasthaus, Tim Januschowski. (2021). āEnd-to-End Learning of Coherent Probabilistic Forecasts for Hierarchical Time Seriesā. Proceedings of the 38th International Conference on Machine Learning (ICML)." + }, + { + "objectID": "evaluation.html#energy-score", + "href": "evaluation.html#energy-score", + "title": "Hierarchical Evaluation", + "section": "Energy Score", + "text": "Energy Score\n\nsource\n\nenergy_score\n\n energy_score (y, y_sample1, y_sample2, beta=2)\n\nEnergy Score\nCalculates Gneitingās Energy Score sample approximation for y and independent multivariate samples y_sample1 and y_sample2. The Energy Score generalizes the CRPS (beta=1) in the multivariate setting.\n\\[ \\mathrm{ES}(\\mathbf{y}_{\\tau}, \\mathbf{\\hat{y}}_{\\tau}, \\mathbf{\\hat{y}}_{\\tau}')\n= \\frac{1}{2} \\mathbb{E}_{\\hat{P}} \\left[ ||\\mathbf{\\hat{y}}_{\\tau} - \\mathbf{\\hat{y}}_{\\tau}'||^{\\beta} \\right]\n- \\mathbb{E}_{\\hat{P}} \\left[ ||\\mathbf{y}_{\\tau} - \\mathbf{\\hat{y}}_{\\tau}||^{\\beta} \\right]\n\\quad \\beta \\in (0,2]\\]\nwhere \\(\\mathbf{\\hat{y}}_{\\tau}, \\mathbf{\\hat{y}}_{\\tau}'\\) are independent samples drawn from \\(\\hat{P}\\).\nParameters: y: numpy array, Actual values of size (n_series, horizon). y_sample1: numpy array, predictive distribution sample of size (n_series, horizon, n_samples). y_sample2: numpy array, predictive distribution sample of size (n_series, horizon, n_samples). beta: float in (0,2], defines the energy scoreās power for the euclidean metric.\nReturns: score: float.\nReferences: - Gneiting, Tilmann, and Adrian E. Raftery. (2007). āStrictly proper scoring rules, prediction and estimationā. Journal of the American Statistical Association. - Anastasios Panagiotelis, Puwasala Gamakumara, George Athanasopoulos, Rob J. Hyndman. (2022). āProbabilistic forecast reconciliation: Properties, evaluation and score optimisationā. European Journal of Operational Research.\n\nsource\n\n\nlog_score\n\n log_score (y, y_hat, cov, allow_singular=True)\n\nLog Score.\nOne of the simplest multivariate probability scoring rules, it evaluates the negative density at the value of the realisation.\n\\[ \\mathrm{LS}(\\mathbf{y}_{\\tau}, \\mathbf{P}(\\theta_{\\tau}))\n= - \\log(f(\\mathbf{y}_{\\tau}, \\theta_{\\tau}))\\]\nwhere \\(f\\) is the density, \\(\\mathbf{P}(\\theta_{\\tau})\\) is a parametric distribution and \\(f(\\mathbf{y}_{\\tau}, \\theta_{\\tau})\\) represents its density. For the moment we only support multivariate normal log score.\n\\[f(\\mathbf{y}_{\\tau}, \\theta_{\\tau}) =\n(2\\pi )^{-k/2}\\det({\\boldsymbol{\\Sigma }})^{-1/2}\n\\,\\exp \\left(\n-{\\frac {1}{2}}(\\mathbf{y}_{\\tau} -\\hat{\\mathbf{y}}_{\\tau})^{\\!{\\mathsf{T}}}\n{\\boldsymbol{\\Sigma }}^{-1}\n(\\mathbf{y}_{\\tau} -\\hat{\\mathbf{y}}_{\\tau})\n\\right)\\]\nParameters: y: numpy array, Actual values of size (n_series, horizon). y_hat: numpy array, Predicted values (n_series, horizon). cov: numpy matrix, Predicted values covariance (n_series, n_series, horizon). allow_singular: bool=True, if true allows singular covariance.\nReturns: score: float.\n\nx = np.linspace(0, 5, 10, endpoint=False)\ny = multivariate_normal.pdf(x, mean=2.5, cov=0.5)\ny" + }, + { + "objectID": "examples/mlframeworksexample.html", + "href": "examples/mlframeworksexample.html", + "title": "Neural/MLForecast", + "section": "", + "text": "This example notebook demonstrates the compatibility of HierarchicalForecastās reconciliation methods with popular machine-learning libraries, specifically NeuralForecast and MLForecast.\nThe notebook utilizes NBEATS and XGBRegressor models to create base forecasts for the TourismLarge Hierarchical Dataset. After that, we use HierarchicalForecast to reconcile the base predictions.\nReferences - Boris N. Oreshkin, Dmitri Carpov, Nicolas Chapados, Yoshua Bengio (2019). āN-BEATS: Neural basis expansion analysis for interpretable time series forecastingā. url: https://arxiv.org/abs/1905.10437 - Tianqi Chen and Carlos Guestrin. āXGBoost: A Scalable Tree Boosting Systemā. In: Proceedings of the 22nd ACM SIGKDD International Conference on Knowledge Discovery and Data Mining. KDD ā16. San Francisco, California, USA: Association for Computing Machinery, 2016, pp. 785ā794. isbn: 9781450342322. doi: 10.1145/2939672.2939785. url: https://doi.org/10.1145/2939672.2939785 (cit. on p. 26).\nYou can run these experiments using CPU or GPU with Google Colab.\nIf you find the code useful, please ā us on Github" + }, + { + "objectID": "examples/mlframeworksexample.html#installing-packages", + "href": "examples/mlframeworksexample.html#installing-packages", + "title": "Neural/MLForecast", + "section": "1. Installing packages", + "text": "1. Installing packages\n\n!pip install datasetsforecast mlforecast \n!pip install git+https://github.com/Nixtla/neuralforecast.git\n!pip install git+https://github.com/Nixtla/hierarchicalforecast.git\n\n\nimport numpy as np\nimport pandas as pd\n\nfrom datasetsforecast.hierarchical import HierarchicalData\n\nfrom neuralforecast import NeuralForecast\nfrom neuralforecast.models import NBEATS\nfrom neuralforecast.losses.pytorch import GMM\n\nfrom mlforecast import MLForecast\nfrom window_ops.expanding import expanding_mean\nfrom mlforecast.utils import PredictionIntervals\nfrom mlforecast.target_transforms import Differences\nimport xgboost as xgb\n\n#obtain hierarchical reconciliation methods and evaluation\nfrom hierarchicalforecast.methods import BottomUp, MinTrace\nfrom hierarchicalforecast.utils import HierarchicalPlot\nfrom hierarchicalforecast.core import HierarchicalReconciliation\nfrom hierarchicalforecast.evaluation import scaled_crps" + }, + { + "objectID": "examples/mlframeworksexample.html#load-hierarchical-dataset", + "href": "examples/mlframeworksexample.html#load-hierarchical-dataset", + "title": "Neural/MLForecast", + "section": "2. Load hierarchical dataset", + "text": "2. Load hierarchical dataset\nThis detailed Australian Tourism Dataset comes from the National Visitor Survey, managed by the Tourism Research Australia, it is composed of 555 monthly series from 1998 to 2016, it is organized geographically, and purpose of travel. The natural geographical hierarchy comprises seven states, divided further in 27 zones and 76 regions. The purpose of travel categories are holiday, visiting friends and relatives (VFR), business and other. The MinT (Wickramasuriya et al., 2019), among other hierarchical forecasting studies has used the dataset it in the past. The dataset can be accessed in the MinT reconciliation webpage, although other sources are available.\n\n\n\n\n\n\n\n\n\nGeographical Division\nNumber of series per division\nNumber of series per purpose\nTotal\n\n\n\n\nAustralia\n1\n4\n5\n\n\nStates\n7\n28\n35\n\n\nZones\n27\n108\n135\n\n\nRegions\n76\n304\n380\n\n\nTotal\n111\n444\n555\n\n\n\n\nY_df, S_df, tags = HierarchicalData.load('./data', 'TourismLarge')\nY_df['ds'] = pd.to_datetime(Y_df['ds'])\n\n\nY_df.head()\n\n\n \n \n \n\n\n\n\n\n\nunique_id\nds\ny\n\n\n\n\n0\nTotalAll\n1998-01-01\n45151.071280\n\n\n1\nTotalAll\n1998-02-01\n17294.699551\n\n\n2\nTotalAll\n1998-03-01\n20725.114184\n\n\n3\nTotalAll\n1998-04-01\n25388.612353\n\n\n4\nTotalAll\n1998-05-01\n20330.035211\n\n\n\n\n\n\n \n \n \n \n \n \n \n \n \n\n \n \n \n \n\n\nVisualize the aggregation matrix.\n\nhplot = HierarchicalPlot(S=S_df, tags=tags)\nhplot.plot_summing_matrix()\n\n\n\n\nSplit the dataframe in train/test splits.\n\ndef sort_hier_df(Y_df, S_df):\n # sorts unique_id lexicographically\n Y_df.unique_id = Y_df.unique_id.astype('category')\n Y_df.unique_id = Y_df.unique_id.cat.set_categories(S_df.index)\n Y_df = Y_df.sort_values(by=['unique_id', 'ds'])\n return Y_df\n\nY_df = sort_hier_df(Y_df, S_df)\n\n\nhorizon = 12\nY_test_df = Y_df.groupby('unique_id').tail(horizon)\nY_train_df = Y_df.drop(Y_test_df.index)" + }, + { + "objectID": "examples/mlframeworksexample.html#fit-and-predict-models", + "href": "examples/mlframeworksexample.html#fit-and-predict-models", + "title": "Neural/MLForecast", + "section": "3. Fit and Predict Models", + "text": "3. Fit and Predict Models\nHierarchicalForecast is compatible with many different ML models. Here, we show two examples: 1. NBEATS, a MLP-based deep neural architecture. 2. XGBRegressor, a tree-based architecture.\n\nlevel = np.arange(0, 100, 2)\nqs = [[50-lv/2, 50+lv/2] for lv in level]\nquantiles = np.sort(np.concatenate(qs)/100)\n\n#fit/predict NBEATS from NeuralForecast\nnbeats = NBEATS(h=horizon,\n input_size=2*horizon,\n loss=GMM(n_components=10, quantiles=quantiles),\n scaler_type='robust',\n max_steps=2000)\nnf = NeuralForecast(models=[nbeats], freq='MS')\nnf.fit(df=Y_train_df)\nY_hat_nf = nf.predict()\n\n#fit/predict XGBRegressor from MLForecast\nmf = MLForecast(models=[xgb.XGBRegressor()], \n freq='MS',\n lags=[1,2,12,24],\n date_features=['month'],\n )\nmf.fit(Y_train_df, prediction_intervals=PredictionIntervals(n_windows=10, window_size=horizon)) \nY_hat_mf = mf.predict(horizon, level=level).set_index('unique_id')\n\nINFO:lightning_fabric.utilities.seed:Global seed set to 1\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nY_hat_nf\n\n\n \n \n \n\n\n\n\n\n\nds\nNBEATS\nNBEATS-lo-98.0\nNBEATS-lo-96.0\nNBEATS-lo-94.0\nNBEATS-lo-92.0\nNBEATS-lo-90.0\nNBEATS-lo-88.0\nNBEATS-lo-86.0\nNBEATS-lo-84.0\n...\nNBEATS-hi-80.0\nNBEATS-hi-82.0\nNBEATS-hi-84.0\nNBEATS-hi-86.0\nNBEATS-hi-88.0\nNBEATS-hi-90.0\nNBEATS-hi-92.0\nNBEATS-hi-94.0\nNBEATS-hi-96.0\nNBEATS-hi-98.0\n\n\nunique_id\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nTotalAll\n2016-01-01\n44304.039062\n24825.771484\n26974.607422\n27405.914062\n27881.269531\n28640.238281\n29469.513672\n30213.277344\n31009.929688\n...\n51838.828125\n52150.523438\n52404.886719\n52564.652344\n52951.238281\n53216.839844\n53689.351562\n54015.074219\n54545.882812\n55752.621094\n\n\nTotalAll\n2016-02-01\n20877.984375\n17909.365234\n18334.902344\n18577.355469\n18653.085938\n18755.072266\n18839.824219\n18965.947266\n19074.134766\n...\n22756.220703\n22892.509766\n23029.402344\n23133.941406\n23221.666016\n23385.628906\n23587.021484\n23862.343750\n24243.560547\n24526.462891\n\n\nTotalAll\n2016-03-01\n23444.972656\n18971.355469\n19329.705078\n19472.619141\n19756.503906\n19843.703125\n20075.363281\n20126.689453\n20259.271484\n...\n26024.242188\n26116.677734\n26196.498047\n26342.339844\n26535.798828\n26758.476562\n26934.582031\n27097.130859\n27441.996094\n27704.375000\n\n\nTotalAll\n2016-04-01\n28927.132812\n24030.257812\n24540.779297\n24732.566406\n24988.001953\n25160.744141\n25304.658203\n25456.001953\n25567.078125\n...\n31568.966797\n31698.855469\n31856.851562\n32097.916016\n32211.320312\n32345.988281\n32510.902344\n32724.638672\n33078.031250\n33525.035156\n\n\nTotalAll\n2016-05-01\n22716.433594\n19728.511719\n19910.925781\n20089.443359\n20214.955078\n20269.906250\n20355.708984\n20441.349609\n20491.029297\n...\n24937.335938\n25114.396484\n25270.279297\n25446.765625\n25676.287109\n26028.427734\n26440.011719\n27477.541016\n28452.419922\n29793.591797\n\n\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n\n\nGBDOth\n2016-08-01\n4.731373\n-30.691290\n-8.694043\n-2.576124\n-2.196553\n-2.069076\n-1.913422\n-1.854156\n-1.767804\n...\n9.252028\n10.948211\n12.031944\n14.396760\n18.523523\n43.287716\n58.207531\n69.754929\n81.399673\n116.701561\n\n\nGBDOth\n2016-09-01\n5.685491\n-32.813366\n-11.985416\n-2.978264\n-2.413029\n-2.120405\n-1.788605\n-1.673310\n-1.550562\n...\n12.787840\n14.330542\n15.563581\n16.996040\n29.901039\n45.086597\n60.724380\n75.462578\n92.432518\n125.217796\n\n\nGBDOth\n2016-10-01\n4.760162\n-51.105358\n-27.034277\n-8.493114\n-2.859874\n-2.140030\n-1.905673\n-1.764797\n-1.621011\n...\n10.930604\n11.960605\n13.876516\n14.839364\n18.540100\n32.251144\n48.573261\n65.301460\n83.327026\n113.249001\n\n\nGBDOth\n2016-11-01\n6.491304\n-31.302568\n-6.776994\n-2.816422\n-2.196187\n-2.002094\n-1.806302\n-1.613474\n-1.538146\n...\n14.449442\n15.161877\n17.715519\n22.247185\n39.648643\n52.634579\n67.812111\n75.647865\n85.764038\n116.143196\n\n\nGBDOth\n2016-12-01\n6.683663\n-37.663929\n-13.461041\n-2.384047\n-2.037058\n-1.877487\n-1.620457\n-1.436237\n-1.304141\n...\n15.086438\n16.038090\n18.206852\n24.431122\n35.078407\n44.138805\n62.435913\n77.259911\n104.585594\n123.915787\n\n\n\n\n\n6660 rows Ć 102 columns\n\n \n \n \n \n \n \n \n \n \n\n \n \n \n \n\n\n\nY_hat_mf\n\n\n \n \n \n\n\n\n\n\n\nds\nXGBRegressor\nXGBRegressor-lo-98\nXGBRegressor-lo-96\nXGBRegressor-lo-94\nXGBRegressor-lo-92\nXGBRegressor-lo-90\nXGBRegressor-lo-88\nXGBRegressor-lo-86\nXGBRegressor-lo-84\n...\nXGBRegressor-hi-80\nXGBRegressor-hi-82\nXGBRegressor-hi-84\nXGBRegressor-hi-86\nXGBRegressor-hi-88\nXGBRegressor-hi-90\nXGBRegressor-hi-92\nXGBRegressor-hi-94\nXGBRegressor-hi-96\nXGBRegressor-hi-98\n\n\nunique_id\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nTotalAll\n2016-01-01\n43891.531250\n39048.053886\n39398.911368\n39749.768850\n40100.626332\n40451.483815\n40561.804681\n40586.219613\n40610.634545\n...\n47123.598090\n47148.013022\n47172.427955\n47196.842887\n47221.257819\n47331.578685\n47682.436168\n48033.293650\n48384.151132\n48735.008614\n\n\nTotalAll\n2016-02-01\n20715.656250\n18476.756884\n18482.492537\n18488.228190\n18493.963842\n18499.699495\n18539.212692\n18590.789297\n18642.365902\n...\n22685.793388\n22737.369993\n22788.946598\n22840.523203\n22892.099808\n22931.613005\n22937.348658\n22943.084310\n22948.819963\n22954.555616\n\n\nTotalAll\n2016-03-01\n23008.896484\n17292.312227\n17323.859641\n17355.407055\n17386.954469\n17418.501883\n17582.396869\n17793.558844\n18004.720819\n...\n27590.748200\n27801.910175\n28013.072150\n28224.234125\n28435.396100\n28599.291085\n28630.838500\n28662.385914\n28693.933328\n28725.480742\n\n\nTotalAll\n2016-04-01\n27731.050781\n22333.047144\n22537.510145\n22741.973145\n22946.436145\n23150.899146\n23233.881164\n23273.477118\n23313.073071\n...\n32069.836584\n32109.432538\n32149.028491\n32188.624445\n32228.220398\n32311.202417\n32515.665417\n32720.128417\n32924.591418\n33129.054418\n\n\nTotalAll\n2016-05-01\n24898.529297\n21768.004677\n21859.564615\n21951.124552\n22042.684490\n22134.244428\n22222.835407\n22310.366042\n22397.896678\n...\n27224.100644\n27311.631280\n27399.161916\n27486.692551\n27574.223187\n27662.814166\n27754.374104\n27845.934041\n27937.493979\n28029.053917\n\n\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n\n\nGBDOth\n2016-08-01\n8.842277\n-2.504086\n-1.296329\n-0.088571\n1.119187\n2.326944\n2.794274\n2.997165\n3.200056\n...\n14.078715\n14.281606\n14.484497\n14.687388\n14.890279\n15.357609\n16.565366\n17.773124\n18.980882\n20.188639\n\n\nGBDOth\n2016-09-01\n4.991811\n-1.879816\n-1.879816\n-1.879816\n-1.879816\n-1.879816\n-1.635940\n-1.304965\n-0.973990\n...\n10.295662\n10.626637\n10.957612\n11.288587\n11.619561\n11.863438\n11.863438\n11.863438\n11.863438\n11.863438\n\n\nGBDOth\n2016-10-01\n8.647715\n2.339581\n2.339581\n2.339581\n2.339581\n2.339581\n2.339581\n2.339581\n2.339581\n...\n14.955848\n14.955848\n14.955848\n14.955848\n14.955848\n14.955848\n14.955848\n14.955848\n14.955848\n14.955848\n\n\nGBDOth\n2016-11-01\n5.180346\n0.451095\n0.451095\n0.451095\n0.451095\n0.451095\n0.451095\n0.451095\n0.451095\n...\n9.909597\n9.909597\n9.909597\n9.909597\n9.909597\n9.909597\n9.909597\n9.909597\n9.909597\n9.909597\n\n\nGBDOth\n2016-12-01\n6.052622\n1.791351\n1.791351\n1.791351\n1.791351\n1.791351\n1.791351\n1.791351\n1.791351\n...\n10.313892\n10.313892\n10.313892\n10.313892\n10.313892\n10.313892\n10.313892\n10.313892\n10.313892\n10.313892\n\n\n\n\n\n6660 rows Ć 102 columns" + }, + { + "objectID": "examples/mlframeworksexample.html#reconcile-predictions", + "href": "examples/mlframeworksexample.html#reconcile-predictions", + "title": "Neural/MLForecast", + "section": "4. Reconcile Predictions", + "text": "4. Reconcile Predictions\nWith minimal parsing, we can reconcile the raw output predictions with different HierarchicalForecast reconciliation methods.\n\n\n\n\n\n\nReconciliation Methods Availability\n\n\n\n\n\nThe following reconciliation methods require access to insample predictions: - ERM(method='closed'), ERM(method='reg_bu') - TopDown(method='average_proportions'), TopDown(method='proportion_averages') - MiddleOut(top_down_method='average_proportions'), MiddleOut(top_down_method='proportion_averages') - MinTrace(method='wls_var'), MinTrace(method='mint_cov'), MinTrace(method='mint_shrink')\nYou can obtain NeuralForecastās insample predictions via the NeuralForecast.predict_insample method.\nWe are working on making MLForecastās insample predictions available.\n\n\n\n\nreconcilers = [\n BottomUp(),\n MinTrace('ols')\n]\nhrec = HierarchicalReconciliation(reconcilers=reconcilers)\n\nY_rec_nf = hrec.reconcile(Y_hat_df=Y_hat_nf, Y_df = Y_train_df, S=S_df, tags=tags, level=level)\nY_rec_mf = hrec.reconcile(Y_hat_df=Y_hat_mf, Y_df = Y_train_df, S=S_df, tags=tags, level=level)" + }, + { + "objectID": "examples/mlframeworksexample.html#evaluation", + "href": "examples/mlframeworksexample.html#evaluation", + "title": "Neural/MLForecast", + "section": "5. Evaluation", + "text": "5. Evaluation\nTo evaluate we use a scaled variation of the CRPS, as proposed by Rangapuram (2021), to measure the accuracy of predicted quantiles y_hat compared to the observation y.\n\\[ \\mathrm{sCRPS}(\\hat{F}_{\\tau}, \\mathbf{y}_{\\tau}) = \\frac{2}{N} \\sum_{i}\n\\int^{1}_{0}\n\\frac{\\mathrm{QL}(\\hat{F}_{i,\\tau}, y_{i,\\tau})_{q}}{\\sum_{i} | y_{i,\\tau} |} dq \\]\n\nrec_model_names_nf = ['NBEATS/BottomUp', 'NBEATS/MinTrace_method-ols']\nrec_model_names_mf = ['XGBRegressor/BottomUp', 'XGBRegressor/MinTrace_method-ols']\n\nn_quantiles = len(quantiles)\nn_series = len(S_df)\n\nfor name in rec_model_names_nf:\n quantile_columns = [col for col in Y_rec_nf.columns if (name+'-lo') in col or (name+'-hi') in col]\n y_rec = Y_rec_nf[quantile_columns].values \n y_test = Y_test_df['y'].values\n\n y_rec = y_rec.reshape(n_series, horizon, n_quantiles)\n y_test = y_test.reshape(n_series, horizon)\n scrps = scaled_crps(y=y_test, y_hat=y_rec, quantiles=quantiles)\n print(\"{:<40} {:.5f}\".format(name+\":\", scrps))\n\nfor name in rec_model_names_mf:\n quantile_columns = [col for col in Y_rec_mf.columns if (name+'-lo') in col or (name+'-hi') in col]\n y_rec = Y_rec_mf[quantile_columns].values \n y_test = Y_test_df['y'].values\n\n y_rec = y_rec.reshape(n_series, horizon, n_quantiles)\n y_test = y_test.reshape(n_series, horizon)\n scrps = scaled_crps(y=y_test, y_hat=y_rec, quantiles=quantiles)\n print(\"{:<40} {:.5f}\".format(name+\":\", scrps))\n\nNBEATS/BottomUp: 0.12853\nNBEATS/MinTrace_method-ols: 0.12945\nXGBRegressor/BottomUp: 0.13202\nXGBRegressor/MinTrace_method-ols: 0.13417" + }, + { + "objectID": "examples/mlframeworksexample.html#visualizations", + "href": "examples/mlframeworksexample.html#visualizations", + "title": "Neural/MLForecast", + "section": "6. Visualizations", + "text": "6. Visualizations\n\nplot_nf = pd.concat([Y_df.set_index(['unique_id', 'ds']), \n Y_rec_nf.set_index('ds', append=True)], axis=1)\nplot_nf = plot_nf.reset_index('ds')\n\nplot_mf = pd.concat([Y_df.set_index(['unique_id', 'ds']), \n Y_rec_mf.set_index('ds', append=True)], axis=1)\nplot_mf = plot_mf.reset_index('ds')\n\n\nhplot.plot_series(\n series='TotalVis',\n Y_df=plot_nf, \n models=['y', 'NBEATS', 'NBEATS/BottomUp', 'NBEATS/MinTrace_method-ols'],\n level=[80]\n)\n\n\n\n\n\nhplot.plot_series(\n series='TotalVis',\n Y_df=plot_mf, \n models=['y', 'XGBRegressor', 'XGBRegressor/BottomUp', 'XGBRegressor/MinTrace_method-ols'],\n level=[80]\n)" + }, + { + "objectID": "examples/installation.html", + "href": "examples/installation.html", + "title": "Install", + "section": "", + "text": "You can install the released version of HierachicalForecast from the Python package index with:\npip install hierarchicalforecast\nor\nconda install -c conda-forge hierarchicalforecast\n\n\n\n\n\n\nTip\n\n\n\nWe recommend installing your libraries inside a python virtual or conda environment.\n\n\n\nUser our env (optional)\nIf you donāt have a Conda environment and need tools like Numba, Pandas, NumPy, Jupyter, StatsModels, and Nbdev you can use ours by following these steps:\n\nClone the HierachicalForecast repo:\n\n$ git clone https://github.com/Nixtla/hierachicalforecast.git && cd hierachicalforecast\n\nCreate the environment using the environment.yml file:\n\n$ conda env create -f environment.yml\n\nActivate the environment:\n\n$ conda activate statsforecast\n\n\n\n\nIf you find the code useful, please ā us on Github" + }, + { + "objectID": "examples/index.html", + "href": "examples/index.html", + "title": "Tutorials", + "section": "", + "text": "Click through to any of these tutorials to get started with HierarchicalForecastās features.\n\n\n\n\n\n\n\n\n\n\nTitle\n\n\n\n\n\n\nBootstrap\n\n\n\n\nGeographical Aggregation (Prison Population)\n\n\n\n\nGeographical Aggregation (Tourism)\n\n\n\n\nGluonTS\n\n\n\n\nInstall\n\n\n\n\nIntroduction\n\n\n\n\nNeural/MLForecast\n\n\n\n\nNon-Negative MinTrace\n\n\n\n\nNormality\n\n\n\n\nPERMBU\n\n\n\n\nProbabilistic Forecast Evaluation\n\n\n\n\nReconciliation Quick Start\n\n\n\n\n\n\nNo matching items\n\nIf you find the code useful, please ā us on Github" + }, + { + "objectID": "examples/australiandomestictourism-intervals.html", + "href": "examples/australiandomestictourism-intervals.html", + "title": "Normality", + "section": "", + "text": "In many cases, only the time series at the lowest level of the hierarchies (bottom time series) are available. HierarchicalForecast has tools to create time series for all hierarchies and also allows you to calculate prediction intervals for all hierarchies. In this notebook we will see how to do it.\n!pip install hierarchicalforecast statsforecast\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\n\n# compute base forecast no coherent\nfrom statsforecast.models import AutoARIMA\nfrom statsforecast.core import StatsForecast\n\n#obtain hierarchical reconciliation methods and evaluation\nfrom hierarchicalforecast.methods import BottomUp, MinTrace\nfrom hierarchicalforecast.utils import aggregate, HierarchicalPlot\nfrom hierarchicalforecast.core import HierarchicalReconciliation\nfrom hierarchicalforecast.evaluation import HierarchicalEvaluation\n\n/Users/fedex/miniconda3/envs/hierarchicalforecast/lib/python3.10/site-packages/statsforecast/core.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n from tqdm.autonotebook import tqdm\nIf you find the code useful, please ā us on Github" + }, + { + "objectID": "examples/australiandomestictourism-intervals.html#aggregate-bottom-time-series", + "href": "examples/australiandomestictourism-intervals.html#aggregate-bottom-time-series", + "title": "Normality", + "section": "Aggregate bottom time series", + "text": "Aggregate bottom time series\nIn this example we will use the Tourism dataset from the Forecasting: Principles and Practice book. The dataset only contains the time series at the lowest level, so we need to create the time series for all hierarchies.\n\nY_df = pd.read_csv('https://raw.githubusercontent.com/Nixtla/transfer-learning-time-series/main/datasets/tourism.csv')\nY_df = Y_df.rename({'Trips': 'y', 'Quarter': 'ds'}, axis=1)\nY_df.insert(0, 'Country', 'Australia')\nY_df = Y_df[['Country', 'Region', 'State', 'Purpose', 'ds', 'y']]\nY_df['ds'] = Y_df['ds'].str.replace(r'(\\d+) (Q\\d)', r'\\1-\\2', regex=True)\nY_df['ds'] = pd.to_datetime(Y_df['ds'])\nY_df.head()\n\n\n\n\n\n\n\n\nCountry\nRegion\nState\nPurpose\nds\ny\n\n\n\n\n0\nAustralia\nAdelaide\nSouth Australia\nBusiness\n1998-01-01\n135.077690\n\n\n1\nAustralia\nAdelaide\nSouth Australia\nBusiness\n1998-04-01\n109.987316\n\n\n2\nAustralia\nAdelaide\nSouth Australia\nBusiness\n1998-07-01\n166.034687\n\n\n3\nAustralia\nAdelaide\nSouth Australia\nBusiness\n1998-10-01\n127.160464\n\n\n4\nAustralia\nAdelaide\nSouth Australia\nBusiness\n1999-01-01\n137.448533\n\n\n\n\n\n\n\nThe dataset can be grouped in the following non-strictly hierarchical structure.\n\nspec = [\n ['Country'],\n ['Country', 'State'], \n ['Country', 'Purpose'], \n ['Country', 'State', 'Region'], \n ['Country', 'State', 'Purpose'], \n ['Country', 'State', 'Region', 'Purpose']\n]\n\nUsing the aggregate function from HierarchicalForecast we can generate: 1. Y_df: the hierarchical structured series \\(\\mathbf{y}_{[a,b]\\tau}\\) 2. S_df: the aggregation constraings dataframe with \\(S_{[a,b]}\\) 3. tags: a list with the āunique_idsā conforming each aggregation level.\n\nY_df, S_df, tags = aggregate(df=Y_df, spec=spec)\nY_df = Y_df.reset_index()\n\n/Users/fedex/miniconda3/envs/hierarchicalforecast/lib/python3.10/site-packages/sklearn/preprocessing/_encoders.py:828: FutureWarning: `sparse` was renamed to `sparse_output` in version 1.2 and will be removed in 1.4. `sparse_output` is ignored unless you leave `sparse` to its default value.\n warnings.warn(\n\n\n\nY_df.head()\n\n\n\n\n\n\n\n\nunique_id\nds\ny\n\n\n\n\n0\nAustralia\n1998-01-01\n23182.197269\n\n\n1\nAustralia\n1998-04-01\n20323.380067\n\n\n2\nAustralia\n1998-07-01\n19826.640511\n\n\n3\nAustralia\n1998-10-01\n20830.129891\n\n\n4\nAustralia\n1999-01-01\n22087.353380\n\n\n\n\n\n\n\n\nS_df.iloc[:5, :5]\n\n\n\n\n\n\n\n\nAustralia/ACT/Canberra/Business\nAustralia/ACT/Canberra/Holiday\nAustralia/ACT/Canberra/Other\nAustralia/ACT/Canberra/Visiting\nAustralia/New South Wales/Blue Mountains/Business\n\n\n\n\nAustralia\n1.0\n1.0\n1.0\n1.0\n1.0\n\n\nAustralia/ACT\n1.0\n1.0\n1.0\n1.0\n0.0\n\n\nAustralia/New South Wales\n0.0\n0.0\n0.0\n0.0\n1.0\n\n\nAustralia/Northern Territory\n0.0\n0.0\n0.0\n0.0\n0.0\n\n\nAustralia/Queensland\n0.0\n0.0\n0.0\n0.0\n0.0\n\n\n\n\n\n\n\n\ntags['Country/Purpose']\n\narray(['Australia/Business', 'Australia/Holiday', 'Australia/Other',\n 'Australia/Visiting'], dtype=object)\n\n\nWe can visualize the S matrix and the data using the HierarchicalPlot class as follows.\n\nhplot = HierarchicalPlot(S=S_df, tags=tags)\n\n\nhplot.plot_summing_matrix()\n\n\n\n\n\nhplot.plot_hierarchically_linked_series(\n bottom_series='Australia/ACT/Canberra/Holiday',\n Y_df=Y_df.set_index('unique_id')\n)\n\n\n\n\n\nSplit Train/Test sets\nWe use the final two years (8 quarters) as test set.\n\nY_test_df = Y_df.groupby('unique_id').tail(8)\nY_train_df = Y_df.drop(Y_test_df.index)\n\n\nY_test_df = Y_test_df.set_index('unique_id')\nY_train_df = Y_train_df.set_index('unique_id')\n\n\nY_train_df.groupby('unique_id').size()\n\nunique_id\nAustralia 72\nAustralia/ACT 72\nAustralia/ACT/Business 72\nAustralia/ACT/Canberra 72\nAustralia/ACT/Canberra/Business 72\n ..\nAustralia/Western Australia/Experience Perth/Other 72\nAustralia/Western Australia/Experience Perth/Visiting 72\nAustralia/Western Australia/Holiday 72\nAustralia/Western Australia/Other 72\nAustralia/Western Australia/Visiting 72\nLength: 425, dtype: int64" + }, + { + "objectID": "examples/australiandomestictourism-intervals.html#computing-base-forecasts", + "href": "examples/australiandomestictourism-intervals.html#computing-base-forecasts", + "title": "Normality", + "section": "Computing base forecasts", + "text": "Computing base forecasts\nThe following cell computes the base forecasts for each time series in Y_df using the AutoARIMA and model. Observe that Y_hat_df contains the forecasts but they are not coherent. To reconcile the prediction intervals we need to calculate the uncoherent intervals using the level argument of StatsForecast.\n\nfcst = StatsForecast(df=Y_train_df,\n models=[AutoARIMA(season_length=4)], \n freq='QS', n_jobs=-1)\nY_hat_df = fcst.forecast(h=8, fitted=True, level=[80, 90])\nY_fitted_df = fcst.forecast_fitted_values()" + }, + { + "objectID": "examples/australiandomestictourism-intervals.html#reconcile-forecasts", + "href": "examples/australiandomestictourism-intervals.html#reconcile-forecasts", + "title": "Normality", + "section": "Reconcile forecasts", + "text": "Reconcile forecasts\nThe following cell makes the previous forecasts coherent using the HierarchicalReconciliation class. Since the hierarchy structure is not strict, we canāt use methods such as TopDown or MiddleOut. In this example we use BottomUp and MinTrace. If you want to calculate prediction intervals, you have to use the level argument as follows.\n\nreconcilers = [\n BottomUp(),\n MinTrace(method='mint_shrink'),\n MinTrace(method='ols')\n]\nhrec = HierarchicalReconciliation(reconcilers=reconcilers)\nY_rec_df = hrec.reconcile(Y_hat_df=Y_hat_df, Y_df=Y_fitted_df, \n S=S_df, tags=tags, level=[80, 90])\n\nThe dataframe Y_rec_df contains the reconciled forecasts.\n\nY_rec_df.head()\n\n\n\n\n\n\n\n\nds\nAutoARIMA\nAutoARIMA-lo-90\nAutoARIMA-lo-80\nAutoARIMA-hi-80\nAutoARIMA-hi-90\nAutoARIMA/BottomUp\nAutoARIMA/BottomUp-lo-90\nAutoARIMA/BottomUp-lo-80\nAutoARIMA/BottomUp-hi-80\n...\nAutoARIMA/MinTrace_method-mint_shrink\nAutoARIMA/MinTrace_method-mint_shrink-lo-90\nAutoARIMA/MinTrace_method-mint_shrink-lo-80\nAutoARIMA/MinTrace_method-mint_shrink-hi-80\nAutoARIMA/MinTrace_method-mint_shrink-hi-90\nAutoARIMA/MinTrace_method-ols\nAutoARIMA/MinTrace_method-ols-lo-90\nAutoARIMA/MinTrace_method-ols-lo-80\nAutoARIMA/MinTrace_method-ols-hi-80\nAutoARIMA/MinTrace_method-ols-hi-90\n\n\nunique_id\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nAustralia\n2016-01-01\n26212.554688\n24694.224609\n25029.580078\n27395.527344\n27730.884766\n24368.099609\n23674.076441\n23827.366706\n24908.832513\n...\n25205.749397\n24453.417115\n24619.586229\n25791.912565\n25958.081679\n26059.047512\n24978.608364\n25217.247087\n26900.847937\n27139.486661\n\n\nAustralia\n2016-04-01\n25033.667969\n23324.066406\n23701.669922\n26365.666016\n26743.269531\n22395.921875\n21629.482078\n21798.767146\n22993.076604\n...\n23720.833190\n22915.772233\n23093.587632\n24348.078748\n24525.894148\n24769.464257\n23554.946551\n23823.199470\n25715.729045\n25983.981963\n\n\nAustralia\n2016-07-01\n24507.027344\n22625.500000\n23041.076172\n25972.978516\n26388.554688\n22004.169922\n21182.945074\n21364.330624\n22644.009219\n...\n23167.123691\n22316.298074\n22504.221604\n23830.025777\n24017.949308\n24205.855344\n22870.661086\n23165.568073\n25246.142616\n25541.049603\n\n\nAustralia\n2016-10-01\n25598.929688\n23559.919922\n24010.281250\n27187.578125\n27637.937500\n22325.056641\n21456.892977\n21648.645996\n23001.467285\n...\n23982.251913\n23087.313715\n23284.980478\n24679.523348\n24877.190111\n25271.861336\n23825.782311\n24145.180634\n26398.542038\n26717.940362\n\n\nAustralia\n2017-01-01\n26982.578125\n24651.535156\n25166.396484\n28798.757812\n29313.619141\n23258.001953\n22296.178714\n22508.618508\n24007.385398\n...\n25002.243615\n24016.747195\n24234.415731\n25770.071498\n25987.740034\n26611.143736\n24959.636647\n25324.408272\n27897.879201\n28262.650825\n\n\n\n\n5 rows Ć 21 columns" + }, + { + "objectID": "examples/australiandomestictourism-intervals.html#plot-forecasts", + "href": "examples/australiandomestictourism-intervals.html#plot-forecasts", + "title": "Normality", + "section": "Plot forecasts", + "text": "Plot forecasts\nThen we can plot the probabilistic forecasts using the following function.\n\nplot_df = pd.concat([Y_df.set_index(['unique_id', 'ds']), \n Y_rec_df.set_index('ds', append=True)], axis=1)\nplot_df = plot_df.reset_index('ds')\n\n\nPlot single time series\n\nhplot.plot_series(\n series='Australia',\n Y_df=plot_df, \n models=['y', 'AutoARIMA', 'AutoARIMA/MinTrace_method-ols'],\n level=[80]\n)\n\n\n\n\n\n# Since we are plotting a bottom time series\n# the probabilistic and mean forecasts\n# are the same\nhplot.plot_series(\n series='Australia/Western Australia/Experience Perth/Visiting',\n Y_df=plot_df, \n models=['y', 'AutoARIMA', 'AutoARIMA/BottomUp'],\n level=[80]\n)\n\n\n\n\n\n\nPlot hierarchichally linked time series\n\nhplot.plot_hierarchically_linked_series(\n bottom_series='Australia/Western Australia/Experience Perth/Visiting',\n Y_df=plot_df, \n models=['y', 'AutoARIMA', 'AutoARIMA/MinTrace_method-ols', 'AutoARIMA/BottomUp'],\n level=[80]\n)\n\n\n\n\n\n# ACT only has Canberra\nhplot.plot_hierarchically_linked_series(\n bottom_series='Australia/ACT/Canberra/Other',\n Y_df=plot_df, \n models=['y', 'AutoARIMA/MinTrace_method-mint_shrink'],\n level=[80, 90]\n)\n\n\n\n\n\n\nReferences\n\nHyndman, R.J., & Athanasopoulos, G. (2021). āForecasting: principles and practice, 3rd edition: Chapter 11: Forecasting hierarchical and grouped series.ā. OTexts: Melbourne, Australia. OTexts.com/fpp3 Accessed on July 2022.\nShanika L. Wickramasuriya, George Athanasopoulos, and Rob J. Hyndman. Optimal forecast reconciliation for hierarchical and grouped time series through trace minimization.Journal of the American Statistical Association, 114(526):804ā819, 2019. doi: 10.1080/01621459.2018.1448825. URL https://robjhyndman.com/publications/mint/." + }, + { + "objectID": "examples/nonnegativereconciliation.html", + "href": "examples/nonnegativereconciliation.html", + "title": "Non-Negative MinTrace", + "section": "", + "text": "Large collections of time series organized into structures at different aggregation levels often require their forecasts to follow their aggregation constraints and to be nonnegative, which poses the challenge of creating novel algorithms capable of coherent forecasts.\nThe HierarchicalForecast package provides a wide collection of Python implementations of hierarchical forecasting algorithms that follow nonnegative hierarchical reconciliation.\nIn this notebook, we will show how to use the HierarchicalForecast package to perform nonnegative reconciliation of forecasts on Wiki2 dataset.\nYou can run these experiments using CPU or GPU with Google Colab.\n!pip install hierarchicalforecast statsforecast datasetsforecast\nIf you find the code useful, please ā us on Github" + }, + { + "objectID": "examples/nonnegativereconciliation.html#load-data", + "href": "examples/nonnegativereconciliation.html#load-data", + "title": "Non-Negative MinTrace", + "section": "1. Load Data", + "text": "1. Load Data\nIn this example we will use the Wiki2 dataset. The following cell gets the time series for the different levels in the hierarchy, the summing dataframe S_df which recovers the full dataset from the bottom level hierarchy and the indices of each hierarchy denoted by tags.\n\nimport numpy as np\nimport pandas as pd\n\nfrom datasetsforecast.hierarchical import HierarchicalData\n\n\nY_df, S_df, tags = HierarchicalData.load('./data', 'Wiki2')\nY_df['ds'] = pd.to_datetime(Y_df['ds'])\n\n\nY_df.head()\n\n\n\n\n\n\n\n\nunique_id\nds\ny\n\n\n\n\n0\nTotal\n2016-01-01\n156508\n\n\n1\nTotal\n2016-01-02\n129902\n\n\n2\nTotal\n2016-01-03\n138203\n\n\n3\nTotal\n2016-01-04\n115017\n\n\n4\nTotal\n2016-01-05\n126042\n\n\n\n\n\n\n\n\nS_df.iloc[:5, :5]\n\n\n\n\n\n\n\n\nde_AAC_AAG_001\nde_AAC_AAG_010\nde_AAC_AAG_014\nde_AAC_AAG_045\nde_AAC_AAG_063\n\n\n\n\nTotal\n1\n1\n1\n1\n1\n\n\nde\n1\n1\n1\n1\n1\n\n\nen\n0\n0\n0\n0\n0\n\n\nfr\n0\n0\n0\n0\n0\n\n\nja\n0\n0\n0\n0\n0\n\n\n\n\n\n\n\n\ntags\n\n{'Views': array(['Total'], dtype=object),\n 'Views/Country': array(['de', 'en', 'fr', 'ja', 'ru', 'zh'], dtype=object),\n 'Views/Country/Access': array(['de_AAC', 'de_DES', 'de_MOB', 'en_AAC', 'en_DES', 'en_MOB',\n 'fr_AAC', 'fr_DES', 'fr_MOB', 'ja_AAC', 'ja_DES', 'ja_MOB',\n 'ru_AAC', 'ru_DES', 'ru_MOB', 'zh_AAC', 'zh_DES', 'zh_MOB'],\n dtype=object),\n 'Views/Country/Access/Agent': array(['de_AAC_AAG', 'de_AAC_SPD', 'de_DES_AAG', 'de_MOB_AAG',\n 'en_AAC_AAG', 'en_AAC_SPD', 'en_DES_AAG', 'en_MOB_AAG',\n 'fr_AAC_AAG', 'fr_AAC_SPD', 'fr_DES_AAG', 'fr_MOB_AAG',\n 'ja_AAC_AAG', 'ja_AAC_SPD', 'ja_DES_AAG', 'ja_MOB_AAG',\n 'ru_AAC_AAG', 'ru_AAC_SPD', 'ru_DES_AAG', 'ru_MOB_AAG',\n 'zh_AAC_AAG', 'zh_AAC_SPD', 'zh_DES_AAG', 'zh_MOB_AAG'],\n dtype=object),\n 'Views/Country/Access/Agent/Topic': array(['de_AAC_AAG_001', 'de_AAC_AAG_010', 'de_AAC_AAG_014',\n 'de_AAC_AAG_045', 'de_AAC_AAG_063', 'de_AAC_AAG_100',\n 'de_AAC_AAG_110', 'de_AAC_AAG_123', 'de_AAC_AAG_143',\n 'de_AAC_SPD_012', 'de_AAC_SPD_074', 'de_AAC_SPD_080',\n 'de_AAC_SPD_105', 'de_AAC_SPD_115', 'de_AAC_SPD_133',\n 'de_DES_AAG_064', 'de_DES_AAG_116', 'de_DES_AAG_131',\n 'de_MOB_AAG_015', 'de_MOB_AAG_020', 'de_MOB_AAG_032',\n 'de_MOB_AAG_059', 'de_MOB_AAG_062', 'de_MOB_AAG_088',\n 'de_MOB_AAG_095', 'de_MOB_AAG_109', 'de_MOB_AAG_122',\n 'de_MOB_AAG_149', 'en_AAC_AAG_044', 'en_AAC_AAG_049',\n 'en_AAC_AAG_075', 'en_AAC_AAG_114', 'en_AAC_AAG_119',\n 'en_AAC_AAG_141', 'en_AAC_SPD_004', 'en_AAC_SPD_011',\n 'en_AAC_SPD_026', 'en_AAC_SPD_048', 'en_AAC_SPD_067',\n 'en_AAC_SPD_126', 'en_AAC_SPD_140', 'en_DES_AAG_016',\n 'en_DES_AAG_024', 'en_DES_AAG_042', 'en_DES_AAG_069',\n 'en_DES_AAG_082', 'en_DES_AAG_102', 'en_MOB_AAG_018',\n 'en_MOB_AAG_022', 'en_MOB_AAG_101', 'en_MOB_AAG_124',\n 'fr_AAC_AAG_029', 'fr_AAC_AAG_046', 'fr_AAC_AAG_070',\n 'fr_AAC_AAG_087', 'fr_AAC_AAG_098', 'fr_AAC_AAG_104',\n 'fr_AAC_AAG_111', 'fr_AAC_AAG_112', 'fr_AAC_AAG_142',\n 'fr_AAC_SPD_025', 'fr_AAC_SPD_027', 'fr_AAC_SPD_035',\n 'fr_AAC_SPD_077', 'fr_AAC_SPD_084', 'fr_AAC_SPD_097',\n 'fr_AAC_SPD_130', 'fr_DES_AAG_023', 'fr_DES_AAG_043',\n 'fr_DES_AAG_051', 'fr_DES_AAG_058', 'fr_DES_AAG_061',\n 'fr_DES_AAG_091', 'fr_DES_AAG_093', 'fr_DES_AAG_094',\n 'fr_DES_AAG_136', 'fr_MOB_AAG_006', 'fr_MOB_AAG_030',\n 'fr_MOB_AAG_066', 'fr_MOB_AAG_117', 'fr_MOB_AAG_120',\n 'fr_MOB_AAG_121', 'fr_MOB_AAG_135', 'fr_MOB_AAG_147',\n 'ja_AAC_AAG_038', 'ja_AAC_AAG_047', 'ja_AAC_AAG_055',\n 'ja_AAC_AAG_076', 'ja_AAC_AAG_099', 'ja_AAC_AAG_128',\n 'ja_AAC_AAG_132', 'ja_AAC_AAG_134', 'ja_AAC_AAG_137',\n 'ja_AAC_SPD_013', 'ja_AAC_SPD_034', 'ja_AAC_SPD_050',\n 'ja_AAC_SPD_060', 'ja_AAC_SPD_078', 'ja_AAC_SPD_106',\n 'ja_DES_AAG_079', 'ja_DES_AAG_081', 'ja_DES_AAG_113',\n 'ja_MOB_AAG_065', 'ja_MOB_AAG_073', 'ja_MOB_AAG_092',\n 'ja_MOB_AAG_127', 'ja_MOB_AAG_129', 'ja_MOB_AAG_144',\n 'ru_AAC_AAG_008', 'ru_AAC_AAG_145', 'ru_AAC_AAG_146',\n 'ru_AAC_SPD_000', 'ru_AAC_SPD_090', 'ru_AAC_SPD_148',\n 'ru_DES_AAG_003', 'ru_DES_AAG_007', 'ru_DES_AAG_017',\n 'ru_DES_AAG_041', 'ru_DES_AAG_071', 'ru_DES_AAG_072',\n 'ru_MOB_AAG_002', 'ru_MOB_AAG_040', 'ru_MOB_AAG_083',\n 'ru_MOB_AAG_086', 'ru_MOB_AAG_103', 'ru_MOB_AAG_107',\n 'ru_MOB_AAG_118', 'ru_MOB_AAG_125', 'zh_AAC_AAG_021',\n 'zh_AAC_AAG_033', 'zh_AAC_AAG_037', 'zh_AAC_AAG_052',\n 'zh_AAC_AAG_057', 'zh_AAC_AAG_085', 'zh_AAC_AAG_108',\n 'zh_AAC_SPD_039', 'zh_AAC_SPD_096', 'zh_DES_AAG_009',\n 'zh_DES_AAG_019', 'zh_DES_AAG_053', 'zh_DES_AAG_054',\n 'zh_DES_AAG_056', 'zh_DES_AAG_068', 'zh_DES_AAG_089',\n 'zh_DES_AAG_139', 'zh_MOB_AAG_005', 'zh_MOB_AAG_028',\n 'zh_MOB_AAG_031', 'zh_MOB_AAG_036', 'zh_MOB_AAG_138'], dtype=object)}\n\n\nWe split the dataframe in train/test splits.\n\nY_test_df = Y_df.groupby('unique_id').tail(7)\nY_train_df = Y_df.drop(Y_test_df.index)\n\n\nY_test_df = Y_test_df.set_index('unique_id')\nY_train_df = Y_train_df.set_index('unique_id')" + }, + { + "objectID": "examples/nonnegativereconciliation.html#base-forecasts", + "href": "examples/nonnegativereconciliation.html#base-forecasts", + "title": "Non-Negative MinTrace", + "section": "2. Base Forecasts", + "text": "2. Base Forecasts\nThe following cell computes the base forecast for each time series using the ETS and naive models. Observe that Y_hat_df contains the forecasts but they are not coherent.\n\nfrom statsforecast.models import ETS, Naive\nfrom statsforecast.core import StatsForecast\n\n\nfcst = StatsForecast(\n df=Y_train_df, \n models=[ETS(season_length=7, model='ZAA'), Naive()], \n freq='D', \n n_jobs=-1\n)\nY_hat_df = fcst.forecast(h=7)\n\nObserve that the ETS model computes negative forecasts for some series.\n\nY_hat_df.query('ETS < 0')\n\n\n\n\n\n\n\n\nds\nETS\nNaive\n\n\nunique_id\n\n\n\n\n\n\n\nde_AAC_AAG_001\n2016-12-25\n-487.601532\n340.0\n\n\nde_AAC_AAG_001\n2016-12-26\n-215.634201\n340.0\n\n\nde_AAC_AAG_001\n2016-12-27\n-173.175613\n340.0\n\n\nde_AAC_AAG_001\n2016-12-30\n-290.836060\n340.0\n\n\nde_AAC_AAG_001\n2016-12-31\n-784.441040\n340.0\n\n\n...\n...\n...\n...\n\n\nzh_AAC_AAG_033\n2016-12-31\n-86.526421\n37.0\n\n\nzh_MOB\n2016-12-26\n-199.534882\n1036.0\n\n\nzh_MOB\n2016-12-27\n-69.527260\n1036.0\n\n\nzh_MOB_AAG\n2016-12-26\n-199.534882\n1036.0\n\n\nzh_MOB_AAG\n2016-12-27\n-69.527260\n1036.0\n\n\n\n\n99 rows Ć 3 columns" + }, + { + "objectID": "examples/nonnegativereconciliation.html#non-negative-reconciliation", + "href": "examples/nonnegativereconciliation.html#non-negative-reconciliation", + "title": "Non-Negative MinTrace", + "section": "3. Non-Negative Reconciliation", + "text": "3. Non-Negative Reconciliation\nThe following cell makes the previous forecasts coherent and nonnegative using the HierarchicalReconciliation class.\n\nfrom hierarchicalforecast.methods import MinTrace\nfrom hierarchicalforecast.core import HierarchicalReconciliation\n\n\nreconcilers = [\n MinTrace(method='ols'),\n MinTrace(method='ols', nonnegative=True)\n]\nhrec = HierarchicalReconciliation(reconcilers=reconcilers)\nY_rec_df = hrec.reconcile(Y_hat_df=Y_hat_df, Y_df=Y_train_df,\n S=S_df, tags=tags)\n\nObserve that the nonnegative reconciliation method obtains nonnegative forecasts.\n\nY_rec_df.query('`ETS/MinTrace_method-ols_nonnegative-True` < 0')\n\n\n\n\n\n\n\n\nds\nETS\nNaive\nETS/MinTrace_method-ols\nNaive/MinTrace_method-ols\nETS/MinTrace_method-ols_nonnegative-True\nNaive/MinTrace_method-ols_nonnegative-True\n\n\nunique_id\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nThe free reconciliation method gets negative forecasts.\n\nY_rec_df.query('`ETS/MinTrace_method-ols` < 0')\n\n\n\n\n\n\n\n\nds\nETS\nNaive\nETS/MinTrace_method-ols\nNaive/MinTrace_method-ols\nETS/MinTrace_method-ols_nonnegative-True\nNaive/MinTrace_method-ols_nonnegative-True\n\n\nunique_id\n\n\n\n\n\n\n\n\n\n\n\nde_DES\n2016-12-25\n-2553.932861\n495.0\n-3468.745214\n495.0\n2.262540e-15\n495.0\n\n\nde_DES\n2016-12-26\n-2155.228271\n495.0\n-2985.587125\n495.0\n1.356705e-30\n495.0\n\n\nde_DES\n2016-12-27\n-2720.993896\n495.0\n-3698.680055\n495.0\n6.857413e-30\n495.0\n\n\nde_DES\n2016-12-29\n-3429.432617\n495.0\n-2965.207609\n495.0\n2.456449e+02\n495.0\n\n\nde_DES\n2016-12-30\n-3963.202637\n495.0\n-3217.360371\n495.0\n3.646790e+02\n495.0\n\n\n...\n...\n...\n...\n...\n...\n...\n...\n\n\nzh_MOB_AAG_036\n2016-12-26\n75.298317\n115.0\n-165.799776\n115.0\n3.207772e-14\n115.0\n\n\nzh_MOB_AAG_036\n2016-12-27\n72.895554\n115.0\n-134.340626\n115.0\n2.308198e-14\n115.0\n\n\nzh_MOB_AAG_138\n2016-12-25\n94.796623\n65.0\n-47.009813\n65.0\n3.116938e-14\n65.0\n\n\nzh_MOB_AAG_138\n2016-12-26\n71.293983\n65.0\n-169.804110\n65.0\n0.000000e+00\n65.0\n\n\nzh_MOB_AAG_138\n2016-12-27\n62.049744\n65.0\n-145.186436\n65.0\n0.000000e+00\n65.0\n\n\n\n\n240 rows Ć 7 columns" + }, + { + "objectID": "examples/nonnegativereconciliation.html#evaluation", + "href": "examples/nonnegativereconciliation.html#evaluation", + "title": "Non-Negative MinTrace", + "section": "4. Evaluation", + "text": "4. Evaluation\nThe HierarchicalForecast package includes the HierarchicalEvaluation class to evaluate the different hierarchies and also is capable of compute scaled metrics compared to a benchmark model.\n\nfrom hierarchicalforecast.evaluation import HierarchicalEvaluation\n\n\ndef mse(y, y_hat):\n return np.mean((y-y_hat)**2)\n\nevaluator = HierarchicalEvaluation(evaluators=[mse])\nevaluation = evaluator.evaluate(\n Y_hat_df=Y_rec_df, Y_test_df=Y_test_df, \n tags=tags, benchmark='Naive'\n)\nevaluation.filter(like='ETS', axis=1).T\n\n\n\n\n\n\n\nlevel\nOverall\nViews\nViews/Country\nViews/Country/Access\nViews/Country/Access/Agent\nViews/Country/Access/Agent/Topic\n\n\nmetric\nmse-scaled\nmse-scaled\nmse-scaled\nmse-scaled\nmse-scaled\nmse-scaled\n\n\n\n\nETS\n1.011585\n0.7358\n1.190354\n1.103657\n1.089515\n1.397139\n\n\nETS/MinTrace_method-ols\n0.979163\n0.698355\n1.062521\n1.143277\n1.113349\n1.354041\n\n\nETS/MinTrace_method-ols_nonnegative-True\n0.945075\n0.677892\n1.004639\n1.184719\n1.141442\n1.158672\n\n\n\n\n\n\n\nObserve that the nonnegative reconciliation method performs better that its unconstrained counterpart.\n\nReferences\n\nHyndman, R.J., & Athanasopoulos, G. (2021). āForecasting: principles and practice, 3rd edition: Chapter 11: Forecasting hierarchical and grouped series.ā. OTexts: Melbourne, Australia. OTexts.com/fpp3 Accessed on July 2022.\nWickramasuriya, S. L., Athanasopoulos, G., & Hyndman, R. J. (2019). \"Optimal forecast reconciliation for hierarchical and grouped time series through trace minimization\". Journal of the American Statistical Association, 114 , 804ā819. doi:10.1080/01621459.2018.1448825..\nWickramasuriya, S.L., Turlach, B.A. & Hyndman, R.J. (2020). \"Optimal non-negative forecast reconciliationā. Stat Comput 30, 1167ā1182, https://doi.org/10.1007/s11222-020-09930-0." + }, + { + "objectID": "examples/introduction.html", + "href": "examples/introduction.html", + "title": "Introduction", + "section": "", + "text": "You can run these experiments using CPU or GPU with Google Colab.\nIf you find the code useful, please ā us on Github" + }, + { + "objectID": "examples/introduction.html#hierarchical-series", + "href": "examples/introduction.html#hierarchical-series", + "title": "Introduction", + "section": "1. Hierarchical Series", + "text": "1. Hierarchical Series\nIn many applications, a set of time series is hierarchically organized. Examples include the presence of geographic levels, products, or categories that define different types of aggregations.\nIn such scenarios, forecasters are often required to provide predictions for all disaggregate and aggregate series. A natural desire is for those predictions to be ācoherentā, that is, for the bottom series to add up precisely to the forecasts of the aggregated series.\n\n\n\nFigure 1. A two level time series hierarchical structure, with four bottom level variables.\n\n\nFigure 1. shows a simple hierarchical structure where we have four bottom-level series, two middle-level series, and the top level representing the total aggregation. Its hierarchical aggregations or coherency constraints are:\n\\[\\begin{align}\n y_{\\mathrm{Total},\\tau} = y_{\\beta_{1},\\tau}+y_{\\beta_{2},\\tau}+y_{\\beta_{3},\\tau}+y_{\\beta_{4},\\tau}\n \\qquad \\qquad \\qquad \\qquad \\qquad \\\\\n \\mathbf{y}_{[a],\\tau}=\\left[y_{\\mathrm{Total},\\tau},\\; y_{\\beta_{1},\\tau}+y_{\\beta_{2},\\tau},\\;y_{\\beta_{3},\\tau}+y_{\\beta_{4},\\tau}\\right]^{\\intercal}\n \\qquad\n \\mathbf{y}_{[b],\\tau}=\\left[ y_{\\beta_{1},\\tau},\\; y_{\\beta_{2},\\tau},\\; y_{\\beta_{3},\\tau},\\; y_{\\beta_{4},\\tau} \\right]^{\\intercal}\n\\end{align}\\]\nLuckily these constraints can be compactly expressed with the following matrices:\n\\[\\begin{align}\n\\mathbf{S}_{[a,b][b]}\n=\n\\begin{bmatrix}\n\\mathbf{A}_{\\mathrm{[a][b]}} \\\\\n \\\\\n \\\\\n\\mathbf{I}_{\\mathrm{[b][b]}} \\\\\n \\\\\n\\end{bmatrix}\n=\n\\begin{bmatrix}\n1 & 1 & 1 & 1 \\\\\n1 & 1 & 0 & 0 \\\\\n0 & 0 & 1 & 1 \\\\\n1 & 0 & 0 & 0 \\\\\n0 & 1 & 0 & 0 \\\\\n0 & 0 & 1 & 0 \\\\\n0 & 0 & 0 & 1 \\\\\n\\end{bmatrix}\n\\end{align}\\]\nwhere \\(\\mathbf{A}_{[a,b][b]}\\) aggregates the bottom series to the upper levels, and \\(\\mathbf{I}_{\\mathrm{[b][b]}}\\) is an identity matrix. The representation of the hierarchical series is then:\n\\[\\begin{align}\n\\mathbf{y}_{[a,b],\\tau} = \\mathbf{S}_{[a,b][b]} \\mathbf{y}_{[b],\\tau}\n\\end{align}\\]\nTo visualize an example, in Figure 2. One can think of the hierarchical time series structure levels to represent different geographical aggregations. For example, in Figure 2. the top level is the total aggregation of series within a country, the middle level being its states and the bottom level its regions.\n\n\n\nFigure 2. A hierarchy can be composed of geographic levels. In this example the top level corresponds to country aggregation, middle level to states, and bottom level to regions." + }, + { + "objectID": "examples/introduction.html#hierarchical-forecast", + "href": "examples/introduction.html#hierarchical-forecast", + "title": "Introduction", + "section": "2. Hierarchical Forecast", + "text": "2. Hierarchical Forecast\nTo achieve ācoherencyā, most statistical solutions to the hierarchical forecasting challenge implement a two-stage reconciliation process.\n1. First, we obtain a set of the base forecast \\(\\mathbf{\\hat{y}}_{[a,b],\\tau}\\) 2. Later, we reconcile them into coherent forecasts \\(\\mathbf{\\tilde{y}}_{[a,b],\\tau}\\).\nMost hierarchical reconciliation methods can be expressed by the following transformations:\n\\[\\begin{align}\n\\tilde{\\mathbf{y}}_{[a,b],\\tau} = \\mathbf{S}_{[a,b][b]} \\mathbf{P}_{[b][a,b]} \\hat{\\mathbf{y}}_{[a,b],\\tau}\n\\end{align}\\]\nThe HierarchicalForecast library offers a Python collection of reconciliation methods, datasets, evaluation and visualization tools for the task. Among its available reconciliation methods we have BottomUp, TopDown, MiddleOut, MinTrace, ERM. Among its probabilistic coherent methods we have Normality, Bootstrap, PERMBU." + }, + { + "objectID": "examples/introduction.html#minimal-example", + "href": "examples/introduction.html#minimal-example", + "title": "Introduction", + "section": "3. Minimal Example", + "text": "3. Minimal Example\n\n!pip install hierarchicalforecast\n!pip install -U numba statsforecast datasetsforecast\n\n\nWrangling Data\n\nimport numpy as np\nimport pandas as pd\n\nWe are going to creat a synthetic data set to illustrate a hierarchical time series structure like the one in Figure 1.\nWe will create a two level structure with four bottom series where aggregations of the series are self evident.\n\n# Create Figure 1. synthetic bottom data\nds = pd.date_range(start='2000-01-01', end='2000-08-01', freq='MS')\ny_base = np.arange(1,9)\nr1 = y_base * (10**1)\nr2 = y_base * (10**1)\nr3 = y_base * (10**2)\nr4 = y_base * (10**2)\n\nys = np.concatenate([r1, r2, r3, r4])\nds = np.tile(ds, 4)\nunique_ids = ['r1'] * 8 + ['r2'] * 8 + ['r3'] * 8 + ['r4'] * 8\ntop_level = 'Australia'\nmiddle_level = ['State1'] * 16 + ['State2'] * 16\nbottom_level = unique_ids\n\nbottom_df = dict(ds=ds,\n top_level=top_level, \n middle_level=middle_level, \n bottom_level=bottom_level,\n y=ys)\nbottom_df = pd.DataFrame(bottom_df)\nbottom_df.groupby('bottom_level').head(2)\n\n\n\n\n\n\n\n\nds\ntop_level\nmiddle_level\nbottom_level\ny\n\n\n\n\n0\n2000-01-01\nAustralia\nState1\nr1\n10\n\n\n1\n2000-02-01\nAustralia\nState1\nr1\n20\n\n\n8\n2000-01-01\nAustralia\nState1\nr2\n10\n\n\n9\n2000-02-01\nAustralia\nState1\nr2\n20\n\n\n16\n2000-01-01\nAustralia\nState2\nr3\n100\n\n\n17\n2000-02-01\nAustralia\nState2\nr3\n200\n\n\n24\n2000-01-01\nAustralia\nState2\nr4\n100\n\n\n25\n2000-02-01\nAustralia\nState2\nr4\n200\n\n\n\n\n\n\n\nThe previously introduced hierarchical series \\(\\mathbf{y}_{[a,b]\\tau}\\) is captured within the Y_hier_df dataframe.\nThe aggregation constraints matrix \\(\\mathbf{S}_{[a][b]}\\) is captured within the S_df dataframe.\nFinally the tags contains a list within Y_hier_df composing each hierarchical level, for example the tags['top_level'] contains Australiaās aggregated series index.\n\nfrom hierarchicalforecast.utils import aggregate\n\n\n# Create hierarchical structure and constraints\nhierarchy_levels = [['top_level'],\n ['top_level', 'middle_level'],\n ['top_level', 'middle_level', 'bottom_level']]\nY_hier_df, S_df, tags = aggregate(df=bottom_df, spec=hierarchy_levels)\nY_hier_df = Y_hier_df.reset_index()\nprint('S_df.shape', S_df.shape)\nprint('Y_hier_df.shape', Y_hier_df.shape)\nprint(\"tags['top_level']\", tags['top_level'])\n\nS_df.shape (7, 4)\nY_hier_df.shape (56, 3)\ntags['top_level'] ['Australia']\n\n\n/Users/cchallu/opt/anaconda3/envs/hierarchicalforecast/lib/python3.10/site-packages/sklearn/preprocessing/_encoders.py:828: FutureWarning: `sparse` was renamed to `sparse_output` in version 1.2 and will be removed in 1.4. `sparse_output` is ignored unless you leave `sparse` to its default value.\n warnings.warn(\n\n\n\nY_hier_df.groupby('unique_id').head(2)\n\n\n\n\n\n\n\n\nunique_id\nds\ny\n\n\n\n\n0\nAustralia\n2000-01-01\n220.0\n\n\n1\nAustralia\n2000-02-01\n440.0\n\n\n8\nAustralia/State1\n2000-01-01\n20.0\n\n\n9\nAustralia/State1\n2000-02-01\n40.0\n\n\n16\nAustralia/State2\n2000-01-01\n200.0\n\n\n17\nAustralia/State2\n2000-02-01\n400.0\n\n\n24\nAustralia/State1/r1\n2000-01-01\n10.0\n\n\n25\nAustralia/State1/r1\n2000-02-01\n20.0\n\n\n32\nAustralia/State1/r2\n2000-01-01\n10.0\n\n\n33\nAustralia/State1/r2\n2000-02-01\n20.0\n\n\n40\nAustralia/State2/r3\n2000-01-01\n100.0\n\n\n41\nAustralia/State2/r3\n2000-02-01\n200.0\n\n\n48\nAustralia/State2/r4\n2000-01-01\n100.0\n\n\n49\nAustralia/State2/r4\n2000-02-01\n200.0\n\n\n\n\n\n\n\n\nS_df\n\n\n\n\n\n\n\n\nAustralia/State1/r1\nAustralia/State1/r2\nAustralia/State2/r3\nAustralia/State2/r4\n\n\n\n\nAustralia\n1.0\n1.0\n1.0\n1.0\n\n\nAustralia/State1\n1.0\n1.0\n0.0\n0.0\n\n\nAustralia/State2\n0.0\n0.0\n1.0\n1.0\n\n\nAustralia/State1/r1\n1.0\n0.0\n0.0\n0.0\n\n\nAustralia/State1/r2\n0.0\n1.0\n0.0\n0.0\n\n\nAustralia/State2/r3\n0.0\n0.0\n1.0\n0.0\n\n\nAustralia/State2/r4\n0.0\n0.0\n0.0\n1.0\n\n\n\n\n\n\n\n\n\nBase Predictions\nNext, we compute the base forecast for each time series using the naive model. Observe that Y_hat_df contains the forecasts but they are not coherent.\n\nfrom statsforecast.models import Naive\nfrom statsforecast.core import StatsForecast\n\n\n# Split train/test sets\nY_test_df = Y_hier_df.groupby('unique_id').tail(4)\nY_train_df = Y_hier_df.drop(Y_test_df.index)\n\n# Compute base Naive predictions\n# Careful identifying correct data freq, this data quarterly 'Q'\nfcst = StatsForecast(df=Y_train_df,\n models=[Naive()],\n freq='Q', n_jobs=-1)\nY_hat_df = fcst.forecast(h=4, fitted=True)\nY_fitted_df = fcst.forecast_fitted_values()\n\n\n\nReconciliation\n\nfrom hierarchicalforecast.methods import BottomUp\nfrom hierarchicalforecast.core import HierarchicalReconciliation\n\n\n# You can select a reconciler from our collection\nreconcilers = [BottomUp()] # MinTrace(method='mint_shrink')\nhrec = HierarchicalReconciliation(reconcilers=reconcilers)\n\nY_rec_df = hrec.reconcile(Y_hat_df=Y_hat_df, \n Y_df=Y_fitted_df,\n S=S_df, tags=tags)\nY_rec_df.groupby('unique_id').head(2)\n\n\n\n\n\n\n\n\nds\nNaive\nNaive/BottomUp\n\n\nunique_id\n\n\n\n\n\n\n\nAustralia\n2000-06-30\n880.0\n880.0\n\n\nAustralia\n2000-09-30\n880.0\n880.0\n\n\nAustralia/State1\n2000-06-30\n80.0\n80.0\n\n\nAustralia/State1\n2000-09-30\n80.0\n80.0\n\n\nAustralia/State2\n2000-06-30\n800.0\n800.0\n\n\nAustralia/State2\n2000-09-30\n800.0\n800.0\n\n\nAustralia/State1/r1\n2000-06-30\n40.0\n40.0\n\n\nAustralia/State1/r1\n2000-09-30\n40.0\n40.0\n\n\nAustralia/State1/r2\n2000-06-30\n40.0\n40.0\n\n\nAustralia/State1/r2\n2000-09-30\n40.0\n40.0\n\n\nAustralia/State2/r3\n2000-06-30\n400.0\n400.0\n\n\nAustralia/State2/r3\n2000-09-30\n400.0\n400.0\n\n\nAustralia/State2/r4\n2000-06-30\n400.0\n400.0\n\n\nAustralia/State2/r4\n2000-09-30\n400.0\n400.0" + }, + { + "objectID": "examples/introduction.html#references", + "href": "examples/introduction.html#references", + "title": "Introduction", + "section": "References", + "text": "References\n\nHyndman, R.J., & Athanasopoulos, G. (2021). āForecasting: principles and practice, 3rd edition: Chapter 11: Forecasting hierarchical and grouped series.ā. OTexts: Melbourne, Australia. OTexts.com/fpp3 Accessed on July 2022.\nOrcutt, G.H., Watts, H.W., & Edwards, J.B.(1968). Data aggregation and information loss. The American Economic Review, 58 , 773{787).\nDisaggregation methods to expedite product line forecasting. Journal of Forecasting, 9 , 233ā254. doi:10.1002/for.3980090304.\nWickramasuriya, S. L., Athanasopoulos, G., & Hyndman, R. J. (2019). \"Optimal forecast reconciliation for hierarchical and grouped time series through trace minimization\". Journal of the American Statistical Association, 114 , 804ā819. doi:10.1080/01621459.2018.1448825.\nBen Taieb, S., & Koo, B. (2019). Regularized regression for hierarchical forecasting without unbiasedness conditions. In Proceedings of the 25th ACM SIGKDD International Conference on Knowledge Discovery & Data Mining KDD ā19 (p. 1337{1347). New York, NY, USA: Association for Computing Machinery." + }, + { + "objectID": "examples/tourismlarge-evaluation.html", + "href": "examples/tourismlarge-evaluation.html", + "title": "Probabilistic Forecast Evaluation", + "section": "", + "text": "This notebook offers a step to step guide to create a hierarchical forecasting pipeline.\nIn the pipeline we will use HierarchicalForecast and StatsForecast core class, to create base predictions, reconcile and evaluate them.\nWe will use the TourismL dataset that summarizes large Australian national visitor survey.\nOutline 1. Installing Packages 2. Prepare TourismL dataset - Read and aggregate - StatsForecastās Base Predictions 3. Reconciliar 4. Evaluar\nIf you find the code useful, please ā us on Github" + }, + { + "objectID": "examples/tourismlarge-evaluation.html#installing-hierarchicalforecast", + "href": "examples/tourismlarge-evaluation.html#installing-hierarchicalforecast", + "title": "Probabilistic Forecast Evaluation", + "section": "1. Installing HierarchicalForecast", + "text": "1. Installing HierarchicalForecast\nWe assume you have StatsForecast and HierarchicalForecast already installed, if not check this guide for instructions on how to install HierarchicalForecast.\n\n# %%capture\n# !pip install hierarchicalforecast\n# !pip install -U numba statsforecast datasetsforecast\n\n\nimport os\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\n\nfrom statsforecast.core import StatsForecast\nfrom statsforecast.models import AutoARIMA, Naive\n\nfrom hierarchicalforecast.core import HierarchicalReconciliation\nfrom hierarchicalforecast.evaluation import HierarchicalEvaluation\nfrom hierarchicalforecast.methods import BottomUp, TopDown, MinTrace, ERM\n\nfrom hierarchicalforecast.utils import is_strictly_hierarchical\nfrom hierarchicalforecast.utils import HierarchicalPlot, CodeTimer\nfrom hierarchicalforecast.evaluation import scaled_crps, msse, energy_score\n\nfrom datasetsforecast.hierarchical import HierarchicalData, HierarchicalInfo\n\n/Users/cchallu/opt/anaconda3/envs/hierarchicalforecast/lib/python3.10/site-packages/statsforecast/core.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n from tqdm.autonotebook import tqdm" + }, + { + "objectID": "examples/tourismlarge-evaluation.html#preparing-tourisml-dataset", + "href": "examples/tourismlarge-evaluation.html#preparing-tourisml-dataset", + "title": "Probabilistic Forecast Evaluation", + "section": "2. Preparing TourismL Dataset", + "text": "2. Preparing TourismL Dataset\n\n2.1 Read Hierarchical Dataset\n\n# ['Labour', 'Traffic', 'TourismSmall', 'TourismLarge', 'Wiki2']\ndataset = 'TourismSmall' # 'TourismLarge'\nverbose = True\nintervals_method = 'bootstrap'\nLEVEL = np.arange(0, 100, 2)\nqs = [[50-lv/2, 50+lv/2] for lv in LEVEL]\nQUANTILES = np.sort(np.concatenate(qs)/100)\n\n\nwith CodeTimer('Read and Parse data ', verbose):\n print(f'{dataset}')\n if not os.path.exists('./data'):\n os.makedirs('./data')\n \n dataset_info = HierarchicalInfo[dataset]\n Y_df, S_df, tags = HierarchicalData.load(directory=f'./data/{dataset}', group=dataset)\n Y_df['ds'] = pd.to_datetime(Y_df['ds'])\n\n # Train/Test Splits\n horizon = dataset_info.horizon\n seasonality = dataset_info.seasonality\n Y_test_df = Y_df.groupby('unique_id').tail(horizon)\n Y_train_df = Y_df.drop(Y_test_df.index)\n Y_test_df = Y_test_df.set_index('unique_id')\n Y_train_df = Y_train_df.set_index('unique_id')\n\nTourismSmall\nCode block 'Read and Parse data ' took: 0.99873 seconds\n\n\n100%|āāāāāāāāāā| 1.30M/1.30M [00:00<00:00, 2.74MiB/s]\nINFO:datasetsforecast.utils:Successfully downloaded datasets.zip, 1297279, bytes.\nINFO:datasetsforecast.utils:Decompressing zip file...\nINFO:datasetsforecast.utils:Successfully decompressed data/TourismSmall/hierarchical/datasets.zip\n\n\n\ndataset_info.seasonality\n\n4\n\n\n\nhplot = HierarchicalPlot(S=S_df, tags=tags)\nhplot.plot_summing_matrix()\n\n\n\n\n\nY_train_df\n\n\n\n\n\n\n\n\nds\ny\n\n\nunique_id\n\n\n\n\n\n\ntotal\n1998-03-31\n84503\n\n\ntotal\n1998-06-30\n65312\n\n\ntotal\n1998-09-30\n72753\n\n\ntotal\n1998-12-31\n70880\n\n\ntotal\n1999-03-31\n86893\n\n\n...\n...\n...\n\n\nnt-oth-noncity\n2003-12-31\n132\n\n\nnt-oth-noncity\n2004-03-31\n12\n\n\nnt-oth-noncity\n2004-06-30\n40\n\n\nnt-oth-noncity\n2004-09-30\n186\n\n\nnt-oth-noncity\n2004-12-31\n144\n\n\n\n\n2492 rows Ć 2 columns\n\n\n\n\n\n2.2 StatsForecastās Base Predictions\nThis cell computes the base predictions Y_hat_df for all the series in Y_df using StatsForecastās AutoARIMA. Additionally we obtain insample predictions Y_fitted_df for the methods that require them.\n\nwith CodeTimer('Fit/Predict Model ', verbose):\n # Read to avoid unnecesary AutoARIMA computation\n yhat_file = f'./data/{dataset}/Y_hat.csv'\n yfitted_file = f'./data/{dataset}/Y_fitted.csv'\n\n if os.path.exists(yhat_file):\n Y_hat_df = pd.read_csv(yhat_file)\n Y_fitted_df = pd.read_csv(yfitted_file)\n\n Y_hat_df = Y_hat_df.set_index('unique_id')\n Y_fitted_df = Y_fitted_df.set_index('unique_id')\n\n else:\n fcst = StatsForecast(\n df=Y_train_df, \n models=[AutoARIMA(season_length=seasonality)],\n fallback_model=[Naive()],\n freq='M', \n n_jobs=-1\n )\n Y_hat_df = fcst.forecast(h=horizon, fitted=True, level=LEVEL)\n Y_fitted_df = fcst.forecast_fitted_values()\n Y_hat_df.to_csv(yhat_file)\n Y_fitted_df.to_csv(yfitted_file)\n\n\nY_hat_df\n\n\n\n\n\n\n\n\nds\nAutoARIMA\nAutoARIMA-lo-98\nAutoARIMA-lo-96\nAutoARIMA-lo-94\nAutoARIMA-lo-92\nAutoARIMA-lo-90\nAutoARIMA-lo-88\nAutoARIMA-lo-86\nAutoARIMA-lo-84\n...\nAutoARIMA-hi-80\nAutoARIMA-hi-82\nAutoARIMA-hi-84\nAutoARIMA-hi-86\nAutoARIMA-hi-88\nAutoARIMA-hi-90\nAutoARIMA-hi-92\nAutoARIMA-hi-94\nAutoARIMA-hi-96\nAutoARIMA-hi-98\n\n\nunique_id\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nbus\n2005-01-31\n9673.424805\n7436.356445\n7698.493652\n7864.811523\n7989.925781\n8091.696289\n8178.319336\n8254.270508\n8322.276367\n...\n10905.793945\n10962.725586\n11024.573242\n11092.579102\n11168.530273\n11255.153320\n11356.923828\n11482.038086\n11648.356445\n11910.493164\n\n\nbus\n2005-02-28\n10393.900391\n8156.831543\n8418.968750\n8585.287109\n8710.401367\n8812.171875\n8898.794922\n8974.746094\n9042.751953\n...\n11626.269531\n11683.200195\n11745.048828\n11813.054688\n11889.005859\n11975.628906\n12077.399414\n12202.513672\n12368.832031\n12630.968750\n\n\nbus\n2005-03-31\n12028.134766\n9791.066406\n10053.204102\n10219.521484\n10344.635742\n10446.406250\n10533.029297\n10608.981445\n10676.986328\n...\n13260.503906\n13317.435547\n13379.283203\n13447.289062\n13523.240234\n13609.863281\n13711.633789\n13836.748047\n14003.066406\n14265.203125\n\n\nbus\n2005-04-30\n10995.679688\n8758.610352\n9020.748047\n9187.065430\n9312.179688\n9413.951172\n9500.574219\n9576.525391\n9644.531250\n...\n12228.047852\n12284.979492\n12346.828125\n12414.833008\n12490.785156\n12577.407227\n12679.178711\n12804.292969\n12970.610352\n13232.748047\n\n\nbus\n2005-05-31\n9673.424805\n7262.085449\n7544.643555\n7723.917480\n7858.778320\n7968.477539\n8061.848633\n8143.716797\n8217.019531\n...\n11001.796875\n11063.164062\n11129.830078\n11203.132812\n11285.000977\n11378.372070\n11488.071289\n11622.932617\n11802.206055\n12084.764648\n\n\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n\n\nwa-vfr-noncity\n2005-04-30\n904.125549\n463.371521\n515.018616\n547.787048\n572.437439\n592.488647\n609.555359\n624.519531\n637.918213\n...\n1146.930542\n1158.147339\n1170.332886\n1183.731567\n1198.695679\n1215.762451\n1235.813721\n1260.464111\n1293.232544\n1344.879517\n\n\nwa-vfr-noncity\n2005-05-31\n904.125549\n457.607361\n509.929901\n543.126831\n568.099670\n588.413086\n605.703003\n620.862854\n634.436707\n...\n1150.105957\n1161.469482\n1173.814331\n1187.388184\n1202.548096\n1219.838013\n1240.151489\n1265.124268\n1298.321167\n1350.643677\n\n\nwa-vfr-noncity\n2005-06-30\n904.125549\n451.916687\n504.906036\n538.526062\n563.817139\n584.389465\n601.899719\n617.252808\n630.999634\n...\n1153.240967\n1164.749268\n1177.251465\n1190.998291\n1206.351440\n1223.861694\n1244.433960\n1269.724976\n1303.345093\n1356.334473\n\n\nwa-vfr-noncity\n2005-07-31\n904.125549\n446.296722\n499.944611\n533.982483\n559.587830\n580.415833\n598.143738\n613.687622\n627.605286\n...\n1156.336914\n1167.988159\n1180.645752\n1194.563477\n1210.107422\n1227.835327\n1248.663208\n1274.268677\n1308.306519\n1361.954346\n\n\nwa-vfr-noncity\n2005-08-31\n904.125549\n440.744904\n495.043365\n529.493958\n555.409851\n576.490417\n594.433289\n610.165649\n624.252136\n...\n1159.395264\n1171.187866\n1183.999023\n1198.085449\n1213.817871\n1231.760742\n1252.841309\n1278.757080\n1313.207764\n1367.506226\n\n\n\n\n712 rows Ć 102 columns\n\n\n\n\nY_fitted_df\n\n\n\n\n\n\n\n\nds\ny\nAutoARIMA\nAutoARIMA-lo-98\nAutoARIMA-lo-96\nAutoARIMA-lo-94\nAutoARIMA-lo-92\nAutoARIMA-lo-90\nAutoARIMA-lo-88\nAutoARIMA-lo-86\n...\nAutoARIMA-hi-80\nAutoARIMA-hi-82\nAutoARIMA-hi-84\nAutoARIMA-hi-86\nAutoARIMA-hi-88\nAutoARIMA-hi-90\nAutoARIMA-hi-92\nAutoARIMA-hi-94\nAutoARIMA-hi-96\nAutoARIMA-hi-98\n\n\nunique_id\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nbus\n1998-03-31\n9815.0\n9805.184570\n7568.648926\n7830.724121\n7997.001953\n8122.086426\n8223.833008\n8310.435547\n8386.369141\n...\n11037.260742\n11094.178711\n11156.011719\n11224.000977\n11299.934570\n11386.537109\n11488.283203\n11613.368164\n11779.646484\n12041.720703\n\n\nbus\n1998-06-30\n11823.0\n11811.176758\n9574.640625\n9836.715820\n10002.994141\n10128.078125\n10229.825195\n10316.427734\n10392.361328\n...\n13043.252930\n13100.169922\n13162.003906\n13229.993164\n13305.926758\n13392.528320\n13494.275391\n13619.360352\n13785.637695\n14047.712891\n\n\nbus\n1998-09-30\n13565.0\n13551.434570\n11314.899414\n11576.973633\n11743.251953\n11868.336914\n11970.083008\n12056.685547\n12132.619141\n...\n14783.510742\n14840.428711\n14902.261719\n14970.250977\n15046.184570\n15132.787109\n15234.533203\n15359.618164\n15525.896484\n15787.970703\n\n\nbus\n1998-12-31\n11478.0\n11466.522461\n9229.986328\n9492.060547\n9658.338867\n9783.423828\n9885.169922\n9971.772461\n10047.706055\n...\n12698.597656\n12755.515625\n12817.348633\n12885.337891\n12961.271484\n13047.874023\n13149.620117\n13274.705078\n13440.983398\n13703.057617\n\n\nbus\n1999-03-31\n10027.0\n9845.011719\n7608.475586\n7870.550781\n8036.828613\n8161.913086\n8263.660156\n8350.262695\n8426.195312\n...\n11077.086914\n11134.004883\n11195.838867\n11263.828125\n11339.760742\n11426.363281\n11528.110352\n11653.194336\n11819.472656\n12081.547852\n\n\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n\n\nwa-vfr-noncity\n2003-12-31\n1177.0\n927.351196\n504.362732\n553.928040\n585.375671\n609.032471\n628.275513\n644.654297\n659.015320\n...\n1160.369507\n1171.134155\n1182.828491\n1195.687012\n1210.048096\n1226.426880\n1245.669922\n1269.326660\n1300.774292\n1350.339600\n\n\nwa-vfr-noncity\n2004-03-31\n956.0\n969.565552\n546.577087\n596.142456\n627.590027\n651.246887\n670.489868\n686.868652\n701.229675\n...\n1202.583862\n1213.348511\n1225.042847\n1237.901489\n1252.262451\n1268.641235\n1287.884277\n1311.541016\n1342.988647\n1392.554077\n\n\nwa-vfr-noncity\n2004-06-30\n772.0\n967.268921\n544.280457\n593.845764\n625.293396\n648.950195\n668.193237\n684.572021\n698.933044\n...\n1200.287109\n1211.051880\n1222.746216\n1235.604736\n1249.965820\n1266.344604\n1285.587646\n1309.244385\n1340.692017\n1390.257324\n\n\nwa-vfr-noncity\n2004-09-30\n885.0\n934.251831\n511.263336\n560.828674\n592.276306\n615.933105\n635.176086\n651.554932\n665.915955\n...\n1167.270020\n1178.034790\n1189.729126\n1202.587646\n1216.948730\n1233.327515\n1252.570557\n1276.227295\n1307.674927\n1357.240234\n\n\nwa-vfr-noncity\n2004-12-31\n797.0\n925.923462\n502.934998\n552.500305\n583.947937\n607.604736\n626.847778\n643.226562\n657.587585\n...\n1158.941772\n1169.706421\n1181.400757\n1194.259277\n1208.620361\n1224.999146\n1244.242188\n1267.898926\n1299.346558\n1348.911865\n\n\n\n\n2492 rows Ć 103 columns" + }, + { + "objectID": "examples/tourismlarge-evaluation.html#reconciliate-predictions", + "href": "examples/tourismlarge-evaluation.html#reconciliate-predictions", + "title": "Probabilistic Forecast Evaluation", + "section": "3. Reconciliate Predictions", + "text": "3. Reconciliate Predictions\n\nwith CodeTimer('Reconcile Predictions ', verbose):\n if is_strictly_hierarchical(S=S_df.values.astype(np.float32), \n tags={key: S_df.index.get_indexer(val) for key, val in tags.items()}):\n reconcilers = [\n BottomUp(),\n TopDown(method='average_proportions'),\n TopDown(method='proportion_averages'),\n MinTrace(method='ols'),\n MinTrace(method='wls_var'),\n MinTrace(method='mint_shrink'),\n #ERM(method='reg_bu', lambda_reg=100) # Extremely inneficient\n ERM(method='closed')\n ]\n else:\n reconcilers = [\n BottomUp(),\n MinTrace(method='ols'),\n MinTrace(method='wls_var'),\n MinTrace(method='mint_shrink'),\n #ERM(method='reg_bu', lambda_reg=100) # Extremely inneficient\n ERM(method='closed')\n ]\n \n hrec = HierarchicalReconciliation(reconcilers=reconcilers)\n Y_rec_df = hrec.bootstrap_reconcile(Y_hat_df=Y_hat_df,\n Y_df=Y_fitted_df,\n S_df=S_df, tags=tags,\n level=LEVEL,\n intervals_method=intervals_method,\n num_samples=10, num_seeds=10)\n\n # Matching Y_test/Y_rec/S index ordering\n Y_test_df = Y_test_df.reset_index()\n Y_test_df.unique_id = Y_test_df.unique_id.astype('category')\n Y_test_df.unique_id = Y_test_df.unique_id.cat.set_categories(S_df.index)\n Y_test_df = Y_test_df.sort_values(by=['unique_id', 'ds'])\n\n Y_rec_df = Y_rec_df.reset_index()\n Y_rec_df.unique_id = Y_rec_df.unique_id.astype('category')\n Y_rec_df.unique_id = Y_rec_df.unique_id.cat.set_categories(S_df.index)\n Y_rec_df = Y_rec_df.sort_values(by=['seed', 'unique_id', 'ds'])\n\n # Parsing model level columns\n flat_cols = list(hrec.level_names.keys())\n for model in hrec.level_names:\n flat_cols += hrec.level_names[model]\n for model in hrec.sample_names:\n flat_cols += hrec.sample_names[model]\n y_rec = Y_rec_df[flat_cols]\n model_columns = y_rec.columns\n\n n_series = len(S_df)\n n_seeds = len(Y_rec_df.seed.unique())\n y_rec = y_rec.values.reshape(n_seeds, n_series, horizon, len(model_columns))\n y_test = Y_test_df['y'].values.reshape(n_series, horizon)\n y_train = Y_train_df['y'].values.reshape(n_series, -1)\n\nCode block 'Reconcile Predictions ' took: 11.73492 seconds\n\n\n\n# Qualitative evaluation, of parsed quantiles\nrow_idx = 0\nseed_idx = 0\ncol_idxs = model_columns.get_indexer(hrec.level_names['AutoARIMA/BottomUp'])\nfor i, col in enumerate(col_idxs):\n plt.plot(y_rec[seed_idx, row_idx,:,col], color='orange', alpha=i/100)\nfor i, col in enumerate(col_idxs):\n plt.plot(y_rec[seed_idx+1, row_idx,:,col], color='green', alpha=i/100)\nplt.plot(y_test[row_idx,:], label='True')\nplt.title(f'{S_df.index[row_idx]} Visits \\n' + \\\n f'AutoARIMA/BottomUp-{intervals_method}')\n\nplt.legend()\nplt.grid()\nplt.show()\nplt.close()\n\n\n\n\n\n#Y_rec_df\ntd_levels = hrec.level_names['AutoARIMA/TopDown_method-average_proportions']\nY_rec_df[td_levels]\n\n\n\n\n\n\n\n\nAutoARIMA/TopDown_method-average_proportions-lo-98\nAutoARIMA/TopDown_method-average_proportions-lo-96\nAutoARIMA/TopDown_method-average_proportions-lo-94\nAutoARIMA/TopDown_method-average_proportions-lo-92\nAutoARIMA/TopDown_method-average_proportions-lo-90\nAutoARIMA/TopDown_method-average_proportions-lo-88\nAutoARIMA/TopDown_method-average_proportions-lo-86\nAutoARIMA/TopDown_method-average_proportions-lo-84\nAutoARIMA/TopDown_method-average_proportions-lo-82\nAutoARIMA/TopDown_method-average_proportions-lo-80\n...\nAutoARIMA/TopDown_method-average_proportions-hi-80\nAutoARIMA/TopDown_method-average_proportions-hi-82\nAutoARIMA/TopDown_method-average_proportions-hi-84\nAutoARIMA/TopDown_method-average_proportions-hi-86\nAutoARIMA/TopDown_method-average_proportions-hi-88\nAutoARIMA/TopDown_method-average_proportions-hi-90\nAutoARIMA/TopDown_method-average_proportions-hi-92\nAutoARIMA/TopDown_method-average_proportions-hi-94\nAutoARIMA/TopDown_method-average_proportions-hi-96\nAutoARIMA/TopDown_method-average_proportions-hi-98\n\n\n\n\n0\n80750.389920\n80750.389920\n80750.389920\n82299.061781\n82299.061781\n82299.061781\n82600.022716\n82600.022716\n82600.022716\n82763.007090\n...\n88248.624229\n88248.624229\n88248.624229\n88248.624229\n88384.153447\n90507.444522\n90507.444522\n90507.444522\n90507.444522\n90507.444522\n\n\n1\n61825.843210\n61825.843210\n61825.843210\n61825.843210\n61825.843210\n61825.843210\n63374.515072\n63374.515072\n63374.515072\n63374.515072\n...\n68196.499405\n68196.499405\n68286.705654\n69324.077520\n69324.077520\n69437.018534\n71582.897812\n71582.897812\n71582.897812\n71582.897812\n\n\n2\n68249.624404\n68249.624404\n68249.624404\n68249.624404\n69798.296266\n69798.296266\n69798.296266\n69798.296266\n69798.296266\n69798.296266\n...\n74620.280598\n74620.280598\n74620.280598\n74699.211067\n75747.858714\n75747.858714\n75747.858714\n75815.623322\n78006.679006\n78006.679006\n\n\n3\n67456.030661\n67456.030661\n67456.030661\n67456.030661\n69004.702523\n69004.702523\n69004.702523\n69004.702523\n69004.702523\n69305.663457\n...\n73939.444667\n74954.264971\n74954.264971\n74954.264971\n74954.264971\n74954.264971\n75044.617782\n77213.085263\n77213.085263\n77213.085263\n\n\n4\n80371.819611\n80371.819611\n80371.819611\n80371.819611\n80371.819611\n81827.571161\n81920.491472\n81920.491472\n81920.491472\n81920.491472\n...\n87870.053920\n87870.053920\n87870.053920\n87870.053920\n88005.583138\n90128.874213\n90128.874213\n90128.874213\n90128.874213\n90128.874213\n\n\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n\n\n7115\n132.959504\n132.959504\n132.959504\n132.959504\n132.959504\n135.828870\n136.012021\n136.012021\n136.012021\n136.545910\n...\n147.738932\n147.738932\n147.738932\n152.191189\n152.191189\n152.191189\n152.191189\n152.191189\n152.191189\n152.191189\n\n\n7116\n158.417227\n158.417227\n158.417227\n158.417227\n158.417227\n161.469743\n161.469743\n161.469743\n161.469743\n162.062953\n...\n170.974136\n171.174163\n173.196654\n173.196654\n173.196654\n173.419267\n177.648912\n177.648912\n177.648912\n177.648912\n\n\n7117\n122.066765\n122.066765\n125.119281\n125.119281\n125.119281\n125.119281\n125.712492\n125.712492\n125.712492\n125.712492\n...\n134.623675\n134.623675\n134.801476\n136.846192\n136.846192\n136.846192\n137.024283\n141.298450\n141.298450\n141.298450\n\n\n7118\n134.467576\n134.467576\n134.467576\n134.467576\n137.520093\n137.520093\n137.520093\n137.520093\n138.113303\n138.113303\n...\n145.762241\n145.875843\n147.202288\n149.247004\n149.247004\n149.247004\n149.425094\n153.699262\n153.699262\n153.699262\n\n\n7119\n135.996894\n136.027420\n136.027420\n136.027420\n136.027420\n136.027420\n136.027420\n136.573173\n136.620630\n136.620630\n...\n145.531813\n145.531813\n145.709614\n147.754331\n147.754331\n147.754331\n147.932421\n152.206588\n152.206588\n152.206588\n\n\n\n\n7120 rows Ć 100 columns" + }, + { + "objectID": "examples/tourismlarge-evaluation.html#evaluation", + "href": "examples/tourismlarge-evaluation.html#evaluation", + "title": "Probabilistic Forecast Evaluation", + "section": "4. Evaluation", + "text": "4. Evaluation\n\nwith CodeTimer('Evaluate Models CRPS ', verbose):\n crps_results = {'Dataset': [dataset] * len(['Overall'] + list(tags.keys())),\n 'Level': ['Overall'] + list(tags.keys()),}\n\n for model in hrec.level_names.keys():\n crps_results[model] = []\n for level in crps_results['Level']:\n if level=='Overall':\n row_idxs = np.arange(len(S_df))\n else:\n row_idxs = S_df.index.get_indexer(tags[level])\n col_idxs = model_columns.get_indexer(hrec.level_names[model])\n _y = y_test[row_idxs,:]\n _y_rec_seeds = y_rec[:,row_idxs,:,:][:,:,:,col_idxs]\n\n level_model_crps = []\n for seed_idx in range(y_rec.shape[0]):\n _y_rec = _y_rec_seeds[seed_idx,:,:,:]\n level_model_crps.append(scaled_crps(y=_y, y_hat=_y_rec,\n quantiles=QUANTILES))\n level_model_crps = f'{np.mean(level_model_crps):.4f}Ā±{(1.96 * np.std(level_model_crps)):.4f}'\n crps_results[model].append(level_model_crps)\n\n crps_results = pd.DataFrame(crps_results)\n\ncrps_results\n\nCode block 'Evaluate Models CRPS ' took: 1.13514 seconds\n\n\n\n\n\n\n\n\n\nDataset\nLevel\nAutoARIMA/BottomUp\nAutoARIMA/TopDown_method-average_proportions\nAutoARIMA/TopDown_method-proportion_averages\nAutoARIMA/MinTrace_method-ols\nAutoARIMA/MinTrace_method-wls_var\nAutoARIMA/MinTrace_method-mint_shrink\nAutoARIMA/ERM_method-closed_lambda_reg-0.01\n\n\n\n\n0\nTourismSmall\nOverall\n0.0895Ā±0.0012\n0.1195Ā±0.0008\n0.1197Ā±0.0008\n0.0927Ā±0.0010\n0.0890Ā±0.0010\n0.0898Ā±0.0009\n0.1116Ā±0.0015\n\n\n1\nTourismSmall\nCountry\n0.0481Ā±0.0016\n0.0479Ā±0.0011\n0.0479Ā±0.0011\n0.0504Ā±0.0010\n0.0510Ā±0.0011\n0.0512Ā±0.0011\n0.0525Ā±0.0015\n\n\n2\nTourismSmall\nCountry/Purpose\n0.0699Ā±0.0016\n0.0928Ā±0.0009\n0.0931Ā±0.0009\n0.0804Ā±0.0012\n0.0724Ā±0.0012\n0.0741Ā±0.0012\n0.0927Ā±0.0015\n\n\n3\nTourismSmall\nCountry/Purpose/State\n0.1085Ā±0.0011\n0.1575Ā±0.0009\n0.1579Ā±0.0009\n0.1082Ā±0.0011\n0.1043Ā±0.0009\n0.1049Ā±0.0008\n0.1325Ā±0.0018\n\n\n4\nTourismSmall\nCountry/Purpose/State/CityNonCity\n0.1316Ā±0.0012\n0.1799Ā±0.0008\n0.1800Ā±0.0008\n0.1319Ā±0.0013\n0.1282Ā±0.0011\n0.1290Ā±0.0010\n0.1685Ā±0.0029\n\n\n\n\n\n\n\n\nwith CodeTimer('Evaluate Models MSSE ', verbose):\n msse_results = {'Dataset': [dataset] * len(['Overall'] + list(tags.keys())),\n 'Level': ['Overall'] + list(tags.keys()),}\n for model in hrec.level_names.keys():\n msse_results[model] = []\n for level in msse_results['Level']:\n if level=='Overall':\n row_idxs = np.arange(len(S_df))\n else:\n row_idxs = S_df.index.get_indexer(tags[level])\n col_idx = model_columns.get_loc(model)\n _y = y_test[row_idxs,:]\n _y_train = y_train[row_idxs,:]\n _y_hat_seeds = y_rec[:,row_idxs,:,:][:,:,:,col_idx]\n\n level_model_msse = []\n for seed_idx in range(y_rec.shape[0]):\n _y_hat = _y_hat_seeds[seed_idx,:,:]\n level_model_msse.append(msse(y=_y, y_hat=_y_hat, y_train=_y_train))\n #level_model_msse = f'{np.mean(level_model_msse):.4f}Ā±{(1.96 * np.std(level_model_msse)):.4f}'\n level_model_msse = f'{np.mean(level_model_msse):.4f}'\n msse_results[model].append(level_model_msse)\n\n msse_results = pd.DataFrame(msse_results)\n\nmsse_results\n\nCode block 'Evaluate Models MSSE ' took: 0.73303 seconds\n\n\n\n\n\n\n\n\n\nDataset\nLevel\nAutoARIMA/BottomUp\nAutoARIMA/TopDown_method-average_proportions\nAutoARIMA/TopDown_method-proportion_averages\nAutoARIMA/MinTrace_method-ols\nAutoARIMA/MinTrace_method-wls_var\nAutoARIMA/MinTrace_method-mint_shrink\nAutoARIMA/ERM_method-closed_lambda_reg-0.01\n\n\n\n\n0\nTourismSmall\nOverall\n0.2530\n0.3628\n0.3649\n0.3039\n0.2789\n0.2822\n0.3942\n\n\n1\nTourismSmall\nCountry\n0.2564\n0.3180\n0.3180\n0.3522\n0.3381\n0.3394\n0.4117\n\n\n2\nTourismSmall\nCountry/Purpose\n0.2018\n0.3178\n0.3203\n0.2557\n0.2122\n0.2175\n0.3346\n\n\n3\nTourismSmall\nCountry/Purpose/State\n0.3231\n0.5077\n0.5114\n0.2943\n0.2858\n0.2890\n0.4534\n\n\n4\nTourismSmall\nCountry/Purpose/State/CityNonCity\n0.3423\n0.5047\n0.5099\n0.3238\n0.3083\n0.3115\n0.4791\n\n\n\n\n\n\n\n\nwith CodeTimer('Evaluate Models EScore', verbose):\n energy_results = {'Dataset': [dataset] * len(['Overall'] + list(tags.keys())),\n 'Level': ['Overall'] + list(tags.keys()),}\n for model in hrec.sample_names.keys():\n energy_results[model] = []\n for level in energy_results['Level']:\n if level=='Overall':\n row_idxs = np.arange(len(S_df))\n else:\n row_idxs = S_df.index.get_indexer(tags[level])\n col_idxs = model_columns.get_indexer(hrec.sample_names[model])\n _y = y_test[row_idxs,:]\n _y_sample1 = y_rec[0,row_idxs,:,:][:,:,col_idxs[:len(col_idxs)//2]]\n _y_sample2 = y_rec[0,row_idxs,:,:][:,:,col_idxs[len(col_idxs)//2:]]\n level_model_energy = energy_score(y=_y, \n y_sample1=_y_sample1,\n y_sample2=_y_sample2,\n beta=2)\n energy_results[model].append(level_model_energy)\n energy_results = pd.DataFrame(energy_results)\n\nenergy_results\n\nCode block 'Evaluate Models EScore' took: 0.19443 seconds\n\n\n\n\n\n\n\n\n\nDataset\nLevel\nAutoARIMA/BottomUp\nAutoARIMA/TopDown_method-average_proportions\nAutoARIMA/TopDown_method-proportion_averages\nAutoARIMA/MinTrace_method-ols\nAutoARIMA/MinTrace_method-wls_var\nAutoARIMA/MinTrace_method-mint_shrink\nAutoARIMA/ERM_method-closed_lambda_reg-0.01\n\n\n\n\n0\nTourismSmall\nOverall\n6.874103e+07\n7.917294e+07\n7.962361e+07\n6.930268e+07\n6.914837e+07\n6.955018e+07\n8.235776e+07\n\n\n1\nTourismSmall\nCountry\n3.292999e+07\n2.757131e+07\n2.757129e+07\n3.081254e+07\n3.392861e+07\n3.353851e+07\n3.350023e+07\n\n\n2\nTourismSmall\nCountry/Purpose\n1.894485e+07\n2.661024e+07\n2.683828e+07\n2.218952e+07\n1.932895e+07\n1.984161e+07\n2.681792e+07\n\n\n3\nTourismSmall\nCountry/Purpose/State\n9.393103e+06\n1.408613e+07\n1.419471e+07\n9.016056e+06\n8.778983e+06\n8.928542e+06\n1.211747e+07\n\n\n4\nTourismSmall\nCountry/Purpose/State/CityNonCity\n7.473085e+06\n1.090527e+07\n1.101934e+07\n7.284562e+06\n7.111832e+06\n7.241519e+06\n9.922145e+06" + }, + { + "objectID": "examples/tourismlarge-evaluation.html#references", + "href": "examples/tourismlarge-evaluation.html#references", + "title": "Probabilistic Forecast Evaluation", + "section": "References", + "text": "References\n\nSyama Sundar Rangapuram, Lucien D Werner, Konstantinos Benidis, Pedro Mercado, Jan Gasthaus, Tim Januschowski. (2021). \"End-to-End Learning of Coherent Probabilistic Forecasts for Hierarchical Time Series\". Proceedings of the 38th International Conference on Machine Learning (ICML).\nKin G. Olivares, O. Nganba Meetei, Ruijun Ma, Rohan Reddy, Mengfei Cao, Lee Dicker (2022). āProbabilistic Hierarchical Forecasting with Deep Poisson Mixturesā. Submitted to the International Journal Forecasting, Working paper available at arxiv." + }, + { + "objectID": "methods.html", + "href": "methods.html", + "title": " Reconciliation Methods ", + "section": "", + "text": "Large collections of time series organized into structures at different aggregation levels often require their forecasts to follow their aggregation constraints, which poses the challenge of creating novel algorithms capable of coherent forecasts. The HierarchicalForecast package provides the most comprehensive collection of Python implementations of hierarchical forecasting algorithms that follow classic hierarchical reconciliation. All the methods have a reconcile function capable of reconcile base forecasts using numpy arrays.\nMost reconciliation methods can be described by the following convenient linear algebra notation:\n\\[\\tilde{\\mathbf{y}}_{[a,b],\\tau} = \\mathbf{S}_{[a,b][b]} \\mathbf{P}_{[b][a,b]} \\hat{\\mathbf{y}}_{[a,b],\\tau}\\]\nwhere \\(a, b\\) represent the aggregate and bottom levels, \\(\\mathbf{S}_{[a,b][b]}\\) contains the hierarchical aggregation constraints, and \\(\\mathbf{P}_{[b][a,b]}\\) varies across reconciliation methods. The reconciled predictions are \\(\\tilde{\\mathbf{y}}_{[a,b],\\tau}\\), and the base predictions \\(\\hat{\\mathbf{y}}_{[a,b],\\tau}\\).\n\n 1. Bottom-Up \n\nsource\n\nBottomUpSparse\n\n BottomUpSparse ()\n\nBottomUpSparse Reconciliation Class.\nThis is the implementation of a Bottom Up reconciliation using the sparse matrix approach. It works much more efficient on datasets with many time series. [makoren: At least I hope so, I only checked up until ~20k time series, and thereās no real improvement, it would be great to check for smth like 1M time series, where the dense S matrix really stops fitting in memory]\nSee the parent class for more details.\n\nsource\n\n\nBottomUp\n\n BottomUp ()\n\nBottom Up Reconciliation Class. The most basic hierarchical reconciliation is performed using an Bottom-Up strategy. It was proposed for the first time by Orcutt in 1968. The corresponding hierarchical āprojectionā matrix is defined as: \\[\\mathbf{P}_{\\text{BU}} = [\\mathbf{0}_{\\mathrm{[b],[a]}}\\;|\\;\\mathbf{I}_{\\mathrm{[b][b]}}]\\]\nParameters: None\nReferences: - Orcutt, G.H., Watts, H.W., & Edwards, J.B.(1968). āData aggregation and information lossā. The American Economic Review, 58 , 773{787).\n\nsource\n\n\nBottomUp.fit\n\n BottomUp.fit (S:numpy.ndarray, y_hat:numpy.ndarray,\n idx_bottom:numpy.ndarray,\n y_insample:Optional[numpy.ndarray]=None,\n y_hat_insample:Optional[numpy.ndarray]=None,\n sigmah:Optional[numpy.ndarray]=None,\n intervals_method:Optional[str]=None,\n num_samples:Optional[int]=None, seed:Optional[int]=None,\n tags:Dict[str,numpy.ndarray]=None)\n\nBottom Up Fit Method.\nParameters: S: Summing matrix of size (base, bottom). y_hat: Forecast values of size (base, horizon). idx_bottom: Indices corresponding to the bottom level of S, size (bottom). level: float list 0-100, confidence levels for prediction intervals. intervals_method: Sampler for prediction intevals, one of normality, bootstrap, permbu. **sampler_kwargs: Coherent sampler instantiation arguments.\nReturns: self: object, fitted reconciler.\n\nsource\n\n\nBottomUp.predict\n\n BottomUp.predict (S:numpy.ndarray, y_hat:numpy.ndarray,\n level:Optional[List[int]]=None)\n\nPredict using reconciler.\nPredict using fitted mean and probabilistic reconcilers.\nParameters: S: Summing matrix of size (base, bottom). y_hat: Forecast values of size (base, horizon). level: float list 0-100, confidence levels for prediction intervals.\nReturns: y_tilde: Reconciliated predictions.\n\nsource\n\n\nBottomUp.fit_predict\n\n BottomUp.fit_predict (S:numpy.ndarray, y_hat:numpy.ndarray,\n idx_bottom:numpy.ndarray,\n y_insample:Optional[numpy.ndarray]=None,\n y_hat_insample:Optional[numpy.ndarray]=None,\n sigmah:Optional[numpy.ndarray]=None,\n level:Optional[List[int]]=None,\n intervals_method:Optional[str]=None,\n num_samples:Optional[int]=None,\n seed:Optional[int]=None,\n tags:Dict[str,numpy.ndarray]=None)\n\nBottomUp Reconciliation Method.\nParameters: S: Summing matrix of size (base, bottom). y_hat: Forecast values of size (base, horizon). idx_bottom: Indices corresponding to the bottom level of S, size (bottom). level: float list 0-100, confidence levels for prediction intervals. intervals_method: Sampler for prediction intevals, one of normality, bootstrap, permbu. **sampler_kwargs: Coherent sampler instantiation arguments.\nReturns: y_tilde: Reconciliated y_hat using the Bottom Up approach.\n\nsource\n\n\nBottomUp.sample\n\n BottomUp.sample (num_samples:int)\n\nSample probabilistic coherent distribution.\nGenerates n samples from a probabilistic coherent distribution. The method uses fitted mean and probabilistic reconcilers, defined by the intervals_method selected during the reconcilerās instantiation. Currently available: normality, bootstrap, permbu.\nParameters: num_samples: int, number of samples generated from coherent distribution.\nReturns: samples: Coherent samples of size (num_series, horizon, num_samples).\n\n\n\n 2. Top-Down \n\nsource\n\nTopDown\n\n TopDown (method:str)\n\nTop Down Reconciliation Class.\nThe Top Down hierarchical reconciliation method, distributes the total aggregate predictions and decomposes it down the hierarchy using proportions \\(\\mathbf{p}_{\\mathrm{[b]}}\\) that can be actual historical values or estimated.\n\\[\\mathbf{P}=[\\mathbf{p}_{\\mathrm{[b]}}\\;|\\;\\mathbf{0}_{\\mathrm{[b][a,b\\;-1]}}]\\] Parameters: method: One of forecast_proportions, average_proportions and proportion_averages.\nReferences: - CW. Gross (1990). āDisaggregation methods to expedite product line forecastingā. Journal of Forecasting, 9 , 233ā254. doi:10.1002/for.3980090304. - G. Fliedner (1999). āAn investigation of aggregate variable time series forecast strategies with specific subaggregate time series statistical correlationā. Computers and Operations Research, 26 , 1133ā1149. doi:10.1016/S0305-0548(99)00017-9.\n\nsource\n\n\nTopDown.fit\n\n TopDown.fit (S, y_hat, y_insample:Optional[numpy.ndarray]=None,\n y_hat_insample:Optional[numpy.ndarray]=None,\n sigmah:Optional[numpy.ndarray]=None,\n intervals_method:Optional[str]=None,\n num_samples:Optional[int]=None, seed:Optional[int]=None,\n tags:Dict[str,numpy.ndarray]=None,\n idx_bottom:Optional[numpy.ndarray]=None)\n\nTopDown Fit Method.\nParameters: S: Summing matrix of size (base, bottom). y_hat: Forecast values of size (base, horizon). tags: Each key is a level and each value its S indices. y_insample: Insample values of size (base, insample_size). Optional for forecast_proportions method. idx_bottom: Indices corresponding to the bottom level of S, size (bottom). level: float list 0-100, confidence levels for prediction intervals. intervals_method: Sampler for prediction intevals, one of normality, bootstrap, permbu. **sampler_kwargs: Coherent sampler instantiation arguments.\nReturns: self: object, fitted reconciler.\n\nsource\n\n\nTopDown.predict\n\n TopDown.predict (S:numpy.ndarray, y_hat:numpy.ndarray,\n level:Optional[List[int]]=None)\n\nPredict using reconciler.\nPredict using fitted mean and probabilistic reconcilers.\nParameters: S: Summing matrix of size (base, bottom). y_hat: Forecast values of size (base, horizon). level: float list 0-100, confidence levels for prediction intervals.\nReturns: y_tilde: Reconciliated predictions.\n\nsource\n\n\nTopDown.fit_predict\n\n TopDown.fit_predict (S:numpy.ndarray, y_hat:numpy.ndarray,\n tags:Dict[str,numpy.ndarray],\n idx_bottom:numpy.ndarray=None,\n y_insample:Optional[numpy.ndarray]=None,\n y_hat_insample:Optional[numpy.ndarray]=None,\n sigmah:Optional[numpy.ndarray]=None,\n level:Optional[List[int]]=None,\n intervals_method:Optional[str]=None,\n num_samples:Optional[int]=None,\n seed:Optional[int]=None)\n\nTop Down Reconciliation Method.\nParameters: S: Summing matrix of size (base, bottom). y_hat: Forecast values of size (base, horizon). tags: Each key is a level and each value its S indices. y_insample: Insample values of size (base, insample_size). Optional for forecast_proportions method. idx_bottom: Indices corresponding to the bottom level of S, size (bottom). level: float list 0-100, confidence levels for prediction intervals. intervals_method: Sampler for prediction intevals, one of normality, bootstrap, permbu. **sampler_kwargs: Coherent sampler instantiation arguments.\nReturns: y_tilde: Reconciliated y_hat using the Top Down approach.\n\nsource\n\n\nTopDown.sample\n\n TopDown.sample (num_samples:int)\n\nSample probabilistic coherent distribution.\nGenerates n samples from a probabilistic coherent distribution. The method uses fitted mean and probabilistic reconcilers, defined by the intervals_method selected during the reconcilerās instantiation. Currently available: normality, bootstrap, permbu.\nParameters: num_samples: int, number of samples generated from coherent distribution.\nReturns: samples: Coherent samples of size (num_series, horizon, num_samples).\n\n\n\n 3. Middle-Out \n\nsource\n\nMiddleOut\n\n MiddleOut (middle_level:str, top_down_method:str)\n\nMiddle Out Reconciliation Class.\nThis method is only available for strictly hierarchical structures. It anchors the base predictions in a middle level. The levels above the base predictions use the Bottom-Up approach, while the levels below use a Top-Down.\nParameters: middle_level: Middle level. top_down_method: One of forecast_proportions, average_proportions and proportion_averages.\nReferences: - Hyndman, R.J., & Athanasopoulos, G. (2021). āForecasting: principles and practice, 3rd edition: Chapter 11: Forecasting hierarchical and grouped series.ā. OTexts: Melbourne, Australia. OTexts.com/fpp3 Accessed on July 2022.\n\nsource\n\n\nMiddleOut.fit_predict\n\n MiddleOut.fit_predict (S:numpy.ndarray, y_hat:numpy.ndarray,\n tags:Dict[str,numpy.ndarray],\n y_insample:Optional[numpy.ndarray]=None,\n level:Optional[List[int]]=None,\n intervals_method:Optional[str]=None)\n\nMiddle Out Reconciliation Method.\nParameters: S: Summing matrix of size (base, bottom). y_hat: Forecast values of size (base, horizon). tags: Each key is a level and each value its S indices. y_insample: Insample values of size (base, insample_size). Only used for forecast_proportions\nReturns: y_tilde: Reconciliated y_hat using the Middle Out approach.\n\n\n\n 4. Min-Trace \n\nsource\n\nMinTraceSparse\n\n MinTraceSparse (method:str, nonnegative:bool=False,\n mint_shr_ridge:Optional[float]=2e-08)\n\nMinTraceSparse Reconciliation Class.\nThis is the implementation of a subset of MinTrace features using the sparse matrix approach. It works much more efficient on datasets with many time series.\nSee the parent class for more details.\nCurrently supported: * Methods using diagonal W matrix, i.e. āolsā, āwls_structā, āwls_varā, * The standard MinT version (non-negative is not supported).\nNote: due to the numerical instability of the matrix inversion when creating the P matrix, the method is NOT guaranteed to give identical results to the non-sparse version.\n\nsource\n\n\nMinTrace\n\n MinTrace (method:str, nonnegative:bool=False,\n mint_shr_ridge:Optional[float]=2e-08)\n\nMinTrace Reconciliation Class.\nThis reconciliation algorithm proposed by Wickramasuriya et al. depends on a generalized least squares estimator and an estimator of the covariance matrix of the coherency errors \\(\\mathbf{W}_{h}\\). The Min Trace algorithm minimizes the squared errors for the coherent forecasts under an unbiasedness assumption; the solution has a closed form.\n\\[\\mathbf{P}_{\\text{MinT}}=\\left(\\mathbf{S}^{\\intercal}\\mathbf{W}_{h}\\mathbf{S}\\right)^{-1}\n\\mathbf{S}^{\\intercal}\\mathbf{W}^{-1}_{h}\\]\nParameters: method: str, one of ols, wls_struct, wls_var, mint_shrink, mint_cov. nonnegative: bool, reconciled forecasts should be nonnegative? mint_shr_ridge: float=2e-8, ridge numeric protection to MinTrace-shr covariance estimator.\nReferences: - Wickramasuriya, S. L., Athanasopoulos, G., & Hyndman, R. J. (2019). āOptimal forecast reconciliation for hierarchical and grouped time series through trace minimizationā. Journal of the American Statistical Association, 114 , 804ā819. doi:10.1080/01621459.2018.1448825.. - Wickramasuriya, S.L., Turlach, B.A. & Hyndman, R.J. (2020). āOptimal non-negative forecast reconciliationā. Stat Comput 30, 1167ā1182, https://doi.org/10.1007/s11222-020-09930-0.\n\nsource\n\n\nMinTrace.fit\n\n MinTrace.fit (S, y_hat, y_insample:Optional[numpy.ndarray]=None,\n y_hat_insample:Optional[numpy.ndarray]=None,\n sigmah:Optional[numpy.ndarray]=None,\n intervals_method:Optional[str]=None,\n num_samples:Optional[int]=None, seed:Optional[int]=None,\n tags:Dict[str,numpy.ndarray]=None,\n idx_bottom:Optional[numpy.ndarray]=None)\n\nMinTrace Fit Method.\nParameters: S: Summing matrix of size (base, bottom). y_hat: Forecast values of size (base, horizon). tags: Each key is a level and each value its S indices. y_insample: Insample values of size (base, insample_size). Optional for forecast_proportions method. idx_bottom: Indices corresponding to the bottom level of S, size (bottom). level: float list 0-100, confidence levels for prediction intervals. intervals_method: Sampler for prediction intevals, one of normality, bootstrap, permbu. **sampler_kwargs: Coherent sampler instantiation arguments.\nReturns: self: object, fitted reconciler.\n\nsource\n\n\nMinTrace.predict\n\n MinTrace.predict (S:numpy.ndarray, y_hat:numpy.ndarray,\n level:Optional[List[int]]=None)\n\nPredict using reconciler.\nPredict using fitted mean and probabilistic reconcilers.\nParameters: S: Summing matrix of size (base, bottom). y_hat: Forecast values of size (base, horizon). level: float list 0-100, confidence levels for prediction intervals.\nReturns: y_tilde: Reconciliated predictions.\n\nsource\n\n\nMinTrace.fit_predict\n\n MinTrace.fit_predict (S:numpy.ndarray, y_hat:numpy.ndarray,\n idx_bottom:numpy.ndarray=None,\n y_insample:Optional[numpy.ndarray]=None,\n y_hat_insample:Optional[numpy.ndarray]=None,\n sigmah:Optional[numpy.ndarray]=None,\n level:Optional[List[int]]=None,\n intervals_method:Optional[str]=None,\n num_samples:Optional[int]=None,\n seed:Optional[int]=None,\n tags:Dict[str,numpy.ndarray]=None)\n\nMinTrace Reconciliation Method.\nParameters: S: Summing matrix of size (base, bottom). y_hat: Forecast values of size (base, horizon). y_insample: Insample values of size (base, insample_size). Only used by wls_var, mint_cov, mint_shrink y_hat_insample: Insample fitted values of size (base, insample_size). Only used by wls_var, mint_cov, mint_shrink idx_bottom: Indices corresponding to the bottom level of S, size (bottom). level: float list 0-100, confidence levels for prediction intervals. sampler: Sampler for prediction intevals, one of normality, bootstrap, permbu.\nReturns: y_tilde: Reconciliated y_hat using the MinTrace approach.\n\nsource\n\n\nMinTrace.sample\n\n MinTrace.sample (num_samples:int)\n\nSample probabilistic coherent distribution.\nGenerates n samples from a probabilistic coherent distribution. The method uses fitted mean and probabilistic reconcilers, defined by the intervals_method selected during the reconcilerās instantiation. Currently available: normality, bootstrap, permbu.\nParameters: num_samples: int, number of samples generated from coherent distribution.\nReturns: samples: Coherent samples of size (num_series, horizon, num_samples).\n\n\n\n 5. Optimal Combination \n\nsource\n\nOptimalCombination\n\n OptimalCombination (method:str, nonnegative:bool=False)\n\nOptimal Combination Reconciliation Class.\nThis reconciliation algorithm was proposed by Hyndman et al. 2011, the method uses generalized least squares estimator using the coherency errors covariance matrix. Consider the covariance of the base forecast \\(\\textrm{Var}(\\epsilon_{h}) = \\Sigma_{h}\\), the \\(\\mathbf{P}\\) matrix of this method is defined by: \\[ \\mathbf{P} = \\left(\\mathbf{S}^{\\intercal}\\Sigma_{h}^{\\dagger}\\mathbf{S}\\right)^{-1}\\mathbf{S}^{\\intercal}\\Sigma^{\\dagger}_{h}\\] where \\(\\Sigma_{h}^{\\dagger}\\) denotes the variance pseudo-inverse. The method was later proven equivalent to MinTrace variants.\nParameters: method: str, allowed optimal combination methods: āolsā, āwls_structā. nonnegative: bool, reconciled forecasts should be nonnegative?\nReferences: - Rob J. Hyndman, Roman A. Ahmed, George Athanasopoulos, Han Lin Shang (2010). āOptimal Combination Forecasts for Hierarchical Time Seriesā.. - Shanika L. Wickramasuriya, George Athanasopoulos and Rob J. Hyndman (2010). āOptimal Combination Forecasts for Hierarchical Time Seriesā.. - Wickramasuriya, S.L., Turlach, B.A. & Hyndman, R.J. (2020). āOptimal non-negative forecast reconciliationā. Stat Comput 30, 1167ā1182, https://doi.org/10.1007/s11222-020-09930-0.\n\nsource\n\n\nOptimalCombination.fit\n\n OptimalCombination.fit (S, y_hat,\n y_insample:Optional[numpy.ndarray]=None,\n y_hat_insample:Optional[numpy.ndarray]=None,\n sigmah:Optional[numpy.ndarray]=None,\n intervals_method:Optional[str]=None,\n num_samples:Optional[int]=None,\n seed:Optional[int]=None,\n tags:Dict[str,numpy.ndarray]=None,\n idx_bottom:Optional[numpy.ndarray]=None)\n\nMinTrace Fit Method.\nParameters: S: Summing matrix of size (base, bottom). y_hat: Forecast values of size (base, horizon). tags: Each key is a level and each value its S indices. y_insample: Insample values of size (base, insample_size). Optional for forecast_proportions method. idx_bottom: Indices corresponding to the bottom level of S, size (bottom). level: float list 0-100, confidence levels for prediction intervals. intervals_method: Sampler for prediction intevals, one of normality, bootstrap, permbu. **sampler_kwargs: Coherent sampler instantiation arguments.\nReturns: self: object, fitted reconciler.\n\nsource\n\n\nOptimalCombination.predict\n\n OptimalCombination.predict (S:numpy.ndarray, y_hat:numpy.ndarray,\n level:Optional[List[int]]=None)\n\nPredict using reconciler.\nPredict using fitted mean and probabilistic reconcilers.\nParameters: S: Summing matrix of size (base, bottom). y_hat: Forecast values of size (base, horizon). level: float list 0-100, confidence levels for prediction intervals.\nReturns: y_tilde: Reconciliated predictions.\n\nsource\n\n\nOptimalCombination.fit_predict\n\n OptimalCombination.fit_predict (S:numpy.ndarray, y_hat:numpy.ndarray,\n idx_bottom:numpy.ndarray=None,\n y_insample:Optional[numpy.ndarray]=None, \n y_hat_insample:Optional[numpy.ndarray]=No\n ne, sigmah:Optional[numpy.ndarray]=None,\n level:Optional[List[int]]=None,\n intervals_method:Optional[str]=None,\n num_samples:Optional[int]=None,\n seed:Optional[int]=None,\n tags:Dict[str,numpy.ndarray]=None)\n\nMinTrace Reconciliation Method.\nParameters: S: Summing matrix of size (base, bottom). y_hat: Forecast values of size (base, horizon). y_insample: Insample values of size (base, insample_size). Only used by wls_var, mint_cov, mint_shrink y_hat_insample: Insample fitted values of size (base, insample_size). Only used by wls_var, mint_cov, mint_shrink idx_bottom: Indices corresponding to the bottom level of S, size (bottom). level: float list 0-100, confidence levels for prediction intervals. sampler: Sampler for prediction intevals, one of normality, bootstrap, permbu.\nReturns: y_tilde: Reconciliated y_hat using the MinTrace approach.\n\nsource\n\n\nOptimalCombination.sample\n\n OptimalCombination.sample (num_samples:int)\n\nSample probabilistic coherent distribution.\nGenerates n samples from a probabilistic coherent distribution. The method uses fitted mean and probabilistic reconcilers, defined by the intervals_method selected during the reconcilerās instantiation. Currently available: normality, bootstrap, permbu.\nParameters: num_samples: int, number of samples generated from coherent distribution.\nReturns: samples: Coherent samples of size (num_series, horizon, num_samples).\n\n\n\n 6. Emp. Risk Minimization \n\nsource\n\nERM\n\n ERM (method:str, lambda_reg:float=0.01)\n\nOptimal Combination Reconciliation Class.\nThe Empirical Risk Minimization reconciliation strategy relaxes the unbiasedness assumptions from previous reconciliation methods like MinT and optimizes square errors between the reconciled predictions and the validation data to obtain an optimal reconciliation matrix P.\nThe exact solution for \\(\\mathbf{P}\\) (method='closed') follows the expression: \\[\\mathbf{P}^{*} = \\left(\\mathbf{S}^{\\intercal}\\mathbf{S}\\right)^{-1}\\mathbf{Y}^{\\intercal}\\hat{\\mathbf{Y}}\\left(\\hat{\\mathbf{Y}}\\hat{\\mathbf{Y}}\\right)^{-1}\\]\nThe alternative Lasso regularized \\(\\mathbf{P}\\) solution (method='reg_bu') is useful when the observations of validation data is limited or the exact solution has low numerical stability. \\[\\mathbf{P}^{*} = \\text{argmin}_{\\mathbf{P}} ||\\mathbf{Y}-\\mathbf{S} \\mathbf{P} \\hat{Y} ||^{2}_{2} + \\lambda ||\\mathbf{P}-\\mathbf{P}_{\\text{BU}}||_{1}\\]\nParameters: method: str, one of closed, reg and reg_bu. lambda_reg: float, l1 regularizer for reg and reg_bu.\nReferences: - Ben Taieb, S., & Koo, B. (2019). Regularized regression for hierarchical forecasting without unbiasedness conditions. In Proceedings of the 25th ACM SIGKDD International Conference on Knowledge Discovery & Data Mining KDD ā19 (p. 1337{1347). New York, NY, USA: Association for Computing Machinery..\n\nsource\n\n\nERM.fit\n\n ERM.fit (S, y_hat, y_insample, y_hat_insample,\n sigmah:Optional[numpy.ndarray]=None,\n intervals_method:Optional[str]=None,\n num_samples:Optional[int]=None, seed:Optional[int]=None,\n tags:Dict[str,numpy.ndarray]=None,\n idx_bottom:Optional[numpy.ndarray]=None)\n\nERM Fit Method.\nParameters: S: Summing matrix of size (base, bottom). y_hat: Forecast values of size (base, horizon). y_insample: Train values of size (base, insample_size). y_hat_insample: Insample train predictions of size (base, insample_size). idx_bottom: Indices corresponding to the bottom level of S, size (bottom). level: float list 0-100, confidence levels for prediction intervals. intervals_method: Sampler for prediction intevals, one of normality, bootstrap, permbu. **sampler_kwargs: Coherent sampler instantiation arguments.\nReturns: self: object, fitted reconciler.\n\nsource\n\n\nERM.predict\n\n ERM.predict (S:numpy.ndarray, y_hat:numpy.ndarray,\n level:Optional[List[int]]=None)\n\nPredict using reconciler.\nPredict using fitted mean and probabilistic reconcilers.\nParameters: S: Summing matrix of size (base, bottom). y_hat: Forecast values of size (base, horizon). level: float list 0-100, confidence levels for prediction intervals.\nReturns: y_tilde: Reconciliated predictions.\n\nsource\n\n\nERM.fit_predict\n\n ERM.fit_predict (S:numpy.ndarray, y_hat:numpy.ndarray,\n idx_bottom:numpy.ndarray=None,\n y_insample:Optional[numpy.ndarray]=None,\n y_hat_insample:Optional[numpy.ndarray]=None,\n sigmah:Optional[numpy.ndarray]=None,\n level:Optional[List[int]]=None,\n intervals_method:Optional[str]=None,\n num_samples:Optional[int]=None, seed:Optional[int]=None,\n tags:Dict[str,numpy.ndarray]=None)\n\nERM Reconciliation Method.\nParameters: S: Summing matrix of size (base, bottom). y_hat: Forecast values of size (base, horizon). y_insample: Train values of size (base, insample_size). y_hat_insample: Insample train predictions of size (base, insample_size). idx_bottom: Indices corresponding to the bottom level of S, size (bottom). level: float list 0-100, confidence levels for prediction intervals. intervals_method: Sampler for prediction intevals, one of normality, bootstrap, permbu.\nReturns: y_tilde: Reconciliated y_hat using the ERM approach.\n\nsource\n\n\nERM.sample\n\n ERM.sample (num_samples:int)\n\nSample probabilistic coherent distribution.\nGenerates n samples from a probabilistic coherent distribution. The method uses fitted mean and probabilistic reconcilers, defined by the intervals_method selected during the reconcilerās instantiation. Currently available: normality, bootstrap, permbu.\nParameters: num_samples: int, number of samples generated from coherent distribution.\nReturns: samples: Coherent samples of size (num_series, horizon, num_samples).\n\nreconciler_args = dict(S=S, \n y_hat=y_hat_base,\n y_insample=y_base,\n y_hat_insample=y_hat_base_insample,\n sigmah=sigmah,\n level=[80, 90],\n intervals_method='normality',\n num_samples=200,\n seed=0,\n tags=tags,\n idx_bottom=idx_bottom\n )\n\n\n\n\n References \n\nGeneral Reconciliation\n\nOrcutt, G.H., Watts, H.W., & Edwards, J.B.(1968). Data aggregation and information loss. The American Economic Review, 58 , 773{787).\nDisaggregation methods to expedite product line forecasting. Journal of Forecasting, 9 , 233ā254. doi:10.1002/for.3980090304.\nAn investigation of aggregate variable time series forecast strategies with specific subaggregate time series statistical correlation. Computers and Operations Research, 26 , 1133ā1149. doi:10.1016/S0305-0548(99)00017-9.\nHyndman, R.J., & Athanasopoulos, G. (2021). āForecasting: principles and practice, 3rd edition: Chapter 11: Forecasting hierarchical and grouped series.ā. OTexts: Melbourne, Australia. OTexts.com/fpp3 Accessed on July 2022.\n\n\n\nOptimal Reconciliation\n\nRob J. Hyndman, Roman A. Ahmed, George Athanasopoulos, Han Lin Shang. āOptimal Combination Forecasts for Hierarchical Time Seriesā (2010).\nShanika L. Wickramasuriya, George Athanasopoulos and Rob J. Hyndman. āOptimal Combination Forecasts for Hierarchical Time Seriesā (2010).\nBen Taieb, S., & Koo, B. (2019). Regularized regression for hierarchical forecasting without unbiasedness conditions. In Proceedings of the 25th ACM SIGKDD International Conference on Knowledge Discovery & Data Mining KDD ā19 (p. 1337{1347). New York, NY, USA: Association for Computing Machinery.\n\n\n\nHierarchical Probabilistic Coherent Predictions\n\nPuwasala Gamakumara Ph. D. dissertation. Monash University, Econometrics and Business Statistics. āProbabilistic Forecast Reconciliationā.\nTaieb, Souhaib Ben and Taylor, James W and Hyndman, Rob J. (2017). Coherent probabilistic forecasts for hierarchical time series. International conference on machine learning ICML.\n\n\n\n\n\n\nIf you find the code useful, please ā us on Github" + }, + { + "objectID": "probabilistic_methods.html", + "href": "probabilistic_methods.html", + "title": " Probabilistic Methods ", + "section": "", + "text": "Here we provide a collection of methods designed to provide hierarchically coherent probabilistic distributions, which means that they generate samples of multivariate time series with hierarchical linear constraints.\nWe designed these methods to extend the core.HierarchicalForecast capabilities class. Check their usage example here.\n\n 1. Normality \n\nsource\n\nNormality\n\n Normality (S:numpy.ndarray, P:numpy.ndarray, y_hat:numpy.ndarray,\n sigmah:numpy.ndarray, W:numpy.ndarray, seed:int=0)\n\nNormality Probabilistic Reconciliation Class.\nThe Normality method leverages the Gaussian Distribution linearity, to generate hierarchically coherent prediction distributions. This class is meant to be used as the sampler input as other HierarchicalForecast reconciliation classes.\nGiven base forecasts under a normal distribution: \\[\\hat{y}_{h} \\sim \\mathrm{N}(\\hat{\\boldsymbol{\\mu}}, \\hat{\\mathbf{W}}_{h})\\]\nThe reconciled forecasts are also normally distributed: \\[\\tilde{y}_{h} \\sim \\mathrm{N}(\\mathbf{S}\\mathbf{P}\\hat{\\boldsymbol{\\mu}},\n\\mathbf{S}\\mathbf{P}\\hat{\\mathbf{W}}_{h} \\mathbf{P}^{\\intercal} \\mathbf{S}^{\\intercal})\\]\nParameters: S: np.array, summing matrix of size (base, bottom). P: np.array, reconciliation matrix of size (bottom, base). y_hat: Point forecasts values of size (base, horizon). W: np.array, hierarchical covariance matrix of size (base, base). sigmah: np.array, forecast standard dev. of size (base, horizon). num_samples: int, number of bootstraped samples generated. seed: int, random seed for numpy generatorās replicability.\nReferences: - Panagiotelis A., Gamakumara P. Athanasopoulos G., and Hyndman R. J. (2022). āProbabilistic forecast reconciliation: Properties, evaluation and score optimisationā. European Journal of Operational Research.\n\nsource\n\n\nNormality.get_samples\n\n Normality.get_samples (num_samples:int=None)\n\nNormality Coherent Samples.\nObtains coherent samples under the Normality assumptions.\nParameters: num_samples: int, number of samples generated from coherent distribution.\nReturns: samples: Coherent samples of size (base, horizon, num_samples).\n\n\n\n 2. Bootstrap \n\nsource\n\nBootstrap\n\n Bootstrap (S:numpy.ndarray, P:numpy.ndarray, y_hat:numpy.ndarray,\n y_insample:numpy.ndarray, y_hat_insample:numpy.ndarray,\n num_samples:int=100, seed:int=0, W:numpy.ndarray=None)\n\nBootstrap Probabilistic Reconciliation Class.\nThis method goes beyond the normality assumption for the base forecasts, the technique simulates future sample paths and uses them to generate base sample paths that are latered reconciled. This clever idea and its simplicity allows to generate coherent bootstraped prediction intervals for any reconciliation strategy. This class is meant to be used as the sampler input as other HierarchicalForecast reconciliation classes.\nGiven a boostraped set of simulated sample paths: \\[(\\hat{\\mathbf{y}}^{[1]}_{\\tau}, \\dots ,\\hat{\\mathbf{y}}^{[B]}_{\\tau})\\]\nThe reconciled sample paths allow for reconciled distributional forecasts: \\[(\\mathbf{S}\\mathbf{P}\\hat{\\mathbf{y}}^{[1]}_{\\tau}, \\dots ,\\mathbf{S}\\mathbf{P}\\hat{\\mathbf{y}}^{[B]}_{\\tau})\\]\nParameters: S: np.array, summing matrix of size (base, bottom). P: np.array, reconciliation matrix of size (bottom, base). y_hat: Point forecasts values of size (base, horizon). y_insample: Insample values of size (base, insample_size). y_hat_insample: Insample point forecasts of size (base, insample_size). num_samples: int, number of bootstraped samples generated. seed: int, random seed for numpy generatorās replicability.\nReferences: - Puwasala Gamakumara Ph. D. dissertation. Monash University, Econometrics and Business Statistics (2020). āProbabilistic Forecast Reconciliationā - Panagiotelis A., Gamakumara P. Athanasopoulos G., and Hyndman R. J. (2022). āProbabilistic forecast reconciliation: Properties, evaluation and score optimisationā. European Journal of Operational Research.\n\nsource\n\n\nBootstrap.get_samples\n\n Bootstrap.get_samples (num_samples:int=None)\n\nBootstrap Sample Reconciliation Method.\nApplies Bootstrap sample reconciliation method as defined by Gamakumara 2020. Generating independent sample paths and reconciling them with Bootstrap.\nParameters: num_samples: int, number of samples generated from coherent distribution.\nReturns: samples: Coherent samples of size (base, horizon, num_samples).\n\n\n\n 3. PERMBU \n\nsource\n\nPERMBU\n\n PERMBU (S:numpy.ndarray, tags:Dict[str,numpy.ndarray],\n y_hat:numpy.ndarray, y_insample:numpy.ndarray,\n y_hat_insample:numpy.ndarray, sigmah:numpy.ndarray,\n num_samples:int=None, seed:int=0, P:numpy.ndarray=None)\n\nPERMBU Probabilistic Reconciliation Class.\nThe PERMBU method leverages empirical bottom-level marginal distributions with empirical copula functions (describing bottom-level dependencies) to generate the distribution of aggregate-level distributions using BottomUp reconciliation. The sample reordering technique in the PERMBU method reinjects multivariate dependencies into independent bottom-level samples.\nAlgorithm:\n1. For all series compute conditional marginals distributions.\n2. Compute residuals $\\hat{\\epsilon}_{i,t}$ and obtain rank permutations.\n2. Obtain K-sample from the bottom-level series predictions.\n3. Apply recursively through the hierarchical structure:<br>\n 3.1. For a given aggregate series $i$ and its children series:<br>\n 3.2. Obtain children's empirical joint using sample reordering copula.<br>\n 3.2. From the children's joint obtain the aggregate series's samples. \nParameters: S: np.array, summing matrix of size (base, bottom). tags: Each key is a level and each value its S indices. y_insample: Insample values of size (base, insample_size). y_hat_insample: Insample point forecasts of size (base, insample_size). sigmah: np.array, forecast standard dev. of size (base, horizon). num_samples: int, number of normal prediction samples generated. seed: int, random seed for numpy generatorās replicability.\nReferences: - Taieb, Souhaib Ben and Taylor, James W and Hyndman, Rob J. (2017). Coherent probabilistic forecasts for hierarchical time series. International conference on machine learning ICML.\n\nsource\n\n\nPERMBU.get_samples\n\n PERMBU.get_samples (num_samples:int=None)\n\nPERMBU Sample Reconciliation Method.\nApplies PERMBU reconciliation method as defined by Taieb et. al 2017. Generating independent base prediction samples, restoring its multivariate dependence using estimated copula with reordering and applying the BottomUp aggregation to the new samples.\nParameters: num_samples: int, number of samples generated from coherent distribution.\nReturns: samples: Coherent samples of size (base, horizon, num_samples).\n\n\n\n References \n\nRob J. Hyndman and George Athanasopoulos (2018). āForecasting principles and practice, Reconciled distributional forecastsā.\nPuwasala Gamakumara Ph. D. dissertation. Monash University, Econometrics and Business Statistics (2020). āProbabilistic Forecast Reconciliationā\nPanagiotelis A., Gamakumara P. Athanasopoulos G., and Hyndman R. J. (2022). āProbabilistic forecast reconciliation: Properties, evaluation and score optimisationā. European Journal of Operational Research.\nTaieb, Souhaib Ben and Taylor, James W and Hyndman, Rob J. (2017). Coherent probabilistic forecasts for hierarchical time series. International conference on machine learning ICML.\n\n\n\n\n\nIf you find the code useful, please ā us on Github" + }, + { + "objectID": "examples/australiandomestictourism.html", + "href": "examples/australiandomestictourism.html", + "title": "Geographical Aggregation (Tourism)", + "section": "", + "text": "In many applications, a set of time series is hierarchically organized. Examples include the presence of geographic levels, products, or categories that define different types of aggregations. In such scenarios, forecasters are often required to provide predictions for all disaggregate and aggregate series. A natural desire is for those predictions to be ācoherentā, that is, for the bottom series to add up precisely to the forecasts of the aggregated series.\nIn this notebook we present an example on how to use HierarchicalForecast to produce coherent forecasts between geographical levels. We will use the classic Australian Domestic Tourism (Tourism) dataset, which contains monthly time series of the number of visitors to each state of Australia.\nWe will first load the Tourism data and produce base forecasts using an ETS model from StatsForecast, and then reconciliate the forecasts with several reconciliation algorithms from HierarchicalForecast. Finally, we show the performance is comparable with the results reported by the Forecasting: Principles and Practice which uses the R package fable.\nYou can run these experiments using CPU or GPU with Google Colab.\n!pip install hierarchicalforecast\n!pip install -U statsforecast numba\nIf you find the code useful, please ā us on Github" + }, + { + "objectID": "examples/australiandomestictourism.html#load-and-process-data", + "href": "examples/australiandomestictourism.html#load-and-process-data", + "title": "Geographical Aggregation (Tourism)", + "section": "1. Load and Process Data", + "text": "1. Load and Process Data\nIn this example we will use the Tourism dataset from the Forecasting: Principles and Practice book.\nThe dataset only contains the time series at the lowest level, so we need to create the time series for all hierarchies.\n\nimport numpy as np\nimport pandas as pd\n\n\nY_df = pd.read_csv('https://raw.githubusercontent.com/Nixtla/transfer-learning-time-series/main/datasets/tourism.csv')\nY_df = Y_df.rename({'Trips': 'y', 'Quarter': 'ds'}, axis=1)\nY_df.insert(0, 'Country', 'Australia')\nY_df = Y_df[['Country', 'Region', 'State', 'Purpose', 'ds', 'y']]\nY_df['ds'] = Y_df['ds'].str.replace(r'(\\d+) (Q\\d)', r'\\1-\\2', regex=True)\nY_df['ds'] = pd.to_datetime(Y_df['ds'])\nY_df.head()\n\n\n\n\n\n\n\n\nCountry\nRegion\nState\nPurpose\nds\ny\n\n\n\n\n0\nAustralia\nAdelaide\nSouth Australia\nBusiness\n1998-01-01\n135.077690\n\n\n1\nAustralia\nAdelaide\nSouth Australia\nBusiness\n1998-04-01\n109.987316\n\n\n2\nAustralia\nAdelaide\nSouth Australia\nBusiness\n1998-07-01\n166.034687\n\n\n3\nAustralia\nAdelaide\nSouth Australia\nBusiness\n1998-10-01\n127.160464\n\n\n4\nAustralia\nAdelaide\nSouth Australia\nBusiness\n1999-01-01\n137.448533\n\n\n\n\n\n\n\nThe dataset can be grouped in the following non-strictly hierarchical structure.\n\nspec = [\n ['Country'],\n ['Country', 'State'], \n ['Country', 'Purpose'], \n ['Country', 'State', 'Region'], \n ['Country', 'State', 'Purpose'], \n ['Country', 'State', 'Region', 'Purpose']\n]\n\nUsing the aggregate function from HierarchicalForecast we can get the full set of time series.\n\nfrom hierarchicalforecast.utils import aggregate\n\n\nY_df, S_df, tags = aggregate(Y_df, spec)\nY_df = Y_df.reset_index()\n\n\nY_df.head()\n\n\n\n\n\n\n\n\nunique_id\nds\ny\n\n\n\n\n0\nAustralia\n1998-01-01\n23182.197269\n\n\n1\nAustralia\n1998-04-01\n20323.380067\n\n\n2\nAustralia\n1998-07-01\n19826.640511\n\n\n3\nAustralia\n1998-10-01\n20830.129891\n\n\n4\nAustralia\n1999-01-01\n22087.353380\n\n\n\n\n\n\n\n\nS_df.iloc[:5, :5]\n\n\n\n\n\n\n\n\nAustralia/ACT/Canberra/Business\nAustralia/ACT/Canberra/Holiday\nAustralia/ACT/Canberra/Other\nAustralia/ACT/Canberra/Visiting\nAustralia/New South Wales/Blue Mountains/Business\n\n\n\n\nAustralia\n1.0\n1.0\n1.0\n1.0\n1.0\n\n\nAustralia/ACT\n1.0\n1.0\n1.0\n1.0\n0.0\n\n\nAustralia/New South Wales\n0.0\n0.0\n0.0\n0.0\n1.0\n\n\nAustralia/Northern Territory\n0.0\n0.0\n0.0\n0.0\n0.0\n\n\nAustralia/Queensland\n0.0\n0.0\n0.0\n0.0\n0.0\n\n\n\n\n\n\n\n\ntags['Country/Purpose']\n\narray(['Australia/Business', 'Australia/Holiday', 'Australia/Other',\n 'Australia/Visiting'], dtype=object)\n\n\n\nSplit Train/Test sets\nWe use the final two years (8 quarters) as test set.\n\nY_test_df = Y_df.groupby('unique_id').tail(8)\nY_train_df = Y_df.drop(Y_test_df.index)\n\n\nY_test_df = Y_test_df.set_index('unique_id')\nY_train_df = Y_train_df.set_index('unique_id')\n\n\nY_train_df.groupby('unique_id').size()\n\nunique_id\nAustralia 72\nAustralia/ACT 72\nAustralia/ACT/Business 72\nAustralia/ACT/Canberra 72\nAustralia/ACT/Canberra/Business 72\n ..\nAustralia/Western Australia/Experience Perth/Other 72\nAustralia/Western Australia/Experience Perth/Visiting 72\nAustralia/Western Australia/Holiday 72\nAustralia/Western Australia/Other 72\nAustralia/Western Australia/Visiting 72\nLength: 425, dtype: int64" + }, + { + "objectID": "examples/australiandomestictourism.html#computing-base-forecasts", + "href": "examples/australiandomestictourism.html#computing-base-forecasts", + "title": "Geographical Aggregation (Tourism)", + "section": "2. Computing base forecasts", + "text": "2. Computing base forecasts\nThe following cell computes the base forecasts for each time series in Y_df using the ETS model. Observe that Y_hat_df contains the forecasts but they are not coherent.\n\nfrom statsforecast.models import ETS\nfrom statsforecast.core import StatsForecast\n\n\nfcst = StatsForecast(df=Y_train_df, \n models=[ETS(season_length=4, model='ZZA')], \n freq='QS', n_jobs=-1)\nY_hat_df = fcst.forecast(h=8, fitted=True)\nY_fitted_df = fcst.forecast_fitted_values()" + }, + { + "objectID": "examples/australiandomestictourism.html#reconcile-forecasts", + "href": "examples/australiandomestictourism.html#reconcile-forecasts", + "title": "Geographical Aggregation (Tourism)", + "section": "3. Reconcile forecasts", + "text": "3. Reconcile forecasts\nThe following cell makes the previous forecasts coherent using the HierarchicalReconciliation class. Since the hierarchy structure is not strict, we canāt use methods such as TopDown or MiddleOut. In this example we use BottomUp and MinTrace.\n\nfrom hierarchicalforecast.methods import BottomUp, MinTrace\nfrom hierarchicalforecast.core import HierarchicalReconciliation\n\n\nreconcilers = [\n BottomUp(),\n MinTrace(method='mint_shrink'),\n MinTrace(method='ols')\n]\nhrec = HierarchicalReconciliation(reconcilers=reconcilers)\nY_rec_df = hrec.reconcile(Y_hat_df=Y_hat_df, Y_df=Y_fitted_df, S=S_df, tags=tags)\n\nThe dataframe Y_rec_df contains the reconciled forecasts.\n\nY_rec_df.head()\n\n\n\n\n\n\n\n\nds\nETS\nETS/BottomUp\nETS/MinTrace_method-mint_shrink\nETS/MinTrace_method-ols\n\n\nunique_id\n\n\n\n\n\n\n\n\n\nAustralia\n2016-01-01\n25990.068359\n24379.679688\n25438.888351\n25894.418893\n\n\nAustralia\n2016-04-01\n24458.490234\n22902.664062\n23925.188541\n24357.230480\n\n\nAustralia\n2016-07-01\n23974.056641\n22412.984375\n23440.310338\n23865.929521\n\n\nAustralia\n2016-10-01\n24563.455078\n23127.638672\n24101.001833\n24470.783968\n\n\nAustralia\n2017-01-01\n25990.068359\n24516.175781\n25556.667616\n25901.382401" + }, + { + "objectID": "examples/australiandomestictourism.html#evaluation", + "href": "examples/australiandomestictourism.html#evaluation", + "title": "Geographical Aggregation (Tourism)", + "section": "4. Evaluation", + "text": "4. Evaluation\nThe HierarchicalForecast package includes the HierarchicalEvaluation class to evaluate the different hierarchies and also is capable of compute scaled metrics compared to a benchmark model.\n\nfrom hierarchicalforecast.evaluation import HierarchicalEvaluation\n\n\ndef rmse(y, y_hat):\n return np.mean(np.sqrt(np.mean((y-y_hat)**2, axis=1)))\n\ndef mase(y, y_hat, y_insample, seasonality=4):\n errors = np.mean(np.abs(y - y_hat), axis=1)\n scale = np.mean(np.abs(y_insample[:, seasonality:] - y_insample[:, :-seasonality]), axis=1)\n return np.mean(errors / scale)\n\neval_tags = {}\neval_tags['Total'] = tags['Country']\neval_tags['Purpose'] = tags['Country/Purpose']\neval_tags['State'] = tags['Country/State']\neval_tags['Regions'] = tags['Country/State/Region']\neval_tags['Bottom'] = tags['Country/State/Region/Purpose']\neval_tags['All'] = np.concatenate(list(tags.values()))\n\nevaluator = HierarchicalEvaluation(evaluators=[rmse, mase])\nevaluation = evaluator.evaluate(\n Y_hat_df=Y_rec_df, Y_test_df=Y_test_df,\n tags=eval_tags, Y_df=Y_train_df\n)\nevaluation = evaluation.drop('Overall')\nevaluation.columns = ['Base', 'BottomUp', 'MinTrace(mint_shrink)', 'MinTrace(ols)']\nevaluation = evaluation.applymap('{:.2f}'.format)\n\n/var/folders/rp/97y9_3ns23v01hdn0rp9ndw40000gp/T/ipykernel_46857/2768439279.py:22: PerformanceWarning: dropping on a non-lexsorted multi-index without a level parameter may impact performance.\n evaluation = evaluation.drop('Overall')\n\n\n\nRMSE\nThe following table shows the performance measured using RMSE across levels for each reconciliation method.\n\nevaluation.query('metric == \"rmse\"')\n\n\n\n\n\n\n\n\n\nBase\nBottomUp\nMinTrace(mint_shrink)\nMinTrace(ols)\n\n\nlevel\nmetric\n\n\n\n\n\n\n\n\nTotal\nrmse\n1743.29\n3028.93\n2102.47\n1818.94\n\n\nPurpose\nrmse\n534.75\n791.28\n574.84\n515.53\n\n\nState\nrmse\n308.15\n413.43\n315.89\n287.34\n\n\nRegions\nrmse\n51.65\n55.14\n46.48\n46.29\n\n\nBottom\nrmse\n19.37\n19.37\n17.78\n18.19\n\n\nAll\nrmse\n45.19\n54.95\n44.59\n42.71\n\n\n\n\n\n\n\n\n\nMASE\nThe following table shows the performance measured using MASE across levels for each reconciliation method.\n\nevaluation.query('metric == \"mase\"')\n\n\n\n\n\n\n\n\n\nBase\nBottomUp\nMinTrace(mint_shrink)\nMinTrace(ols)\n\n\nlevel\nmetric\n\n\n\n\n\n\n\n\nTotal\nmase\n1.59\n3.16\n2.05\n1.67\n\n\nPurpose\nmase\n1.32\n2.28\n1.48\n1.25\n\n\nState\nmase\n1.39\n1.90\n1.39\n1.25\n\n\nRegions\nmase\n1.12\n1.19\n1.01\n0.99\n\n\nBottom\nmase\n0.98\n0.98\n0.94\n1.01\n\n\nAll\nmase\n1.03\n1.08\n0.98\n1.02\n\n\n\n\n\n\n\n\n\nComparison fable\nObserve that we can recover the results reported by the Forecasting: Principles and Practice. The original results were calculated using the R package fable.\n\n\n\nFableās reconciliation results\n\n\n\n\nReferences\n\nHyndman, R.J., & Athanasopoulos, G. (2021). āForecasting: principles and practice, 3rd edition: Chapter 11: Forecasting hierarchical and grouped series.ā. OTexts: Melbourne, Australia. OTexts.com/fpp3 Accessed on July 2022.\nRob Hyndman, Alan Lee, Earo Wang, Shanika Wickramasuriya, and Maintainer Earo Wang (2021). āhts: Hierarchical and Grouped Time Seriesā. URL https://CRAN.R-project.org/package=hts. R package version 0.3.1.\nMitchell OāHara-Wild, Rob Hyndman, Earo Wang, Gabriel Caceres, Tim-Gunnar Hensel, and Timothy Hyndman (2021). āfable: Forecasting Models for Tidy Time Seriesā. URL https://CRAN.R-project.org/package=fable. R package version 6.0.2." + }, + { + "objectID": "examples/australiandomestictourism-bootstraped-intervals.html", + "href": "examples/australiandomestictourism-bootstraped-intervals.html", + "title": "Bootstrap", + "section": "", + "text": "In many cases, only the time series at the lowest level of the hierarchies (bottom time series) are available. HierarchicalForecast has tools to create time series for all hierarchies and also allows you to calculate prediction intervals for all hierarchies. In this notebook we will see how to do it.\n!pip install hierarchicalforecast statsforecast\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\n\n# compute base forecast no coherent\nfrom statsforecast.models import ETS, Naive\nfrom statsforecast.core import StatsForecast\n\n#obtain hierarchical reconciliation methods and evaluation\nfrom hierarchicalforecast.methods import BottomUp, MinTrace\nfrom hierarchicalforecast.utils import aggregate, HierarchicalPlot\nfrom hierarchicalforecast.core import HierarchicalReconciliation\nfrom hierarchicalforecast.evaluation import HierarchicalEvaluation\n\n/Users/fedex/miniconda3/envs/hierarchicalforecast/lib/python3.10/site-packages/statsforecast/core.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n from tqdm.autonotebook import tqdm\nIf you find the code useful, please ā us on Github" + }, + { + "objectID": "examples/australiandomestictourism-bootstraped-intervals.html#aggregate-bottom-time-series", + "href": "examples/australiandomestictourism-bootstraped-intervals.html#aggregate-bottom-time-series", + "title": "Bootstrap", + "section": "Aggregate bottom time series", + "text": "Aggregate bottom time series\nIn this example we will use the Tourism dataset from the Forecasting: Principles and Practice book. The dataset only contains the time series at the lowest level, so we need to create the time series for all hierarchies.\n\nY_df = pd.read_csv('https://raw.githubusercontent.com/Nixtla/transfer-learning-time-series/main/datasets/tourism.csv')\nY_df = Y_df.rename({'Trips': 'y', 'Quarter': 'ds'}, axis=1)\nY_df.insert(0, 'Country', 'Australia')\nY_df = Y_df[['Country', 'Region', 'State', 'Purpose', 'ds', 'y']]\nY_df['ds'] = Y_df['ds'].str.replace(r'(\\d+) (Q\\d)', r'\\1-\\2', regex=True)\nY_df['ds'] = pd.to_datetime(Y_df['ds'])\nY_df.head()\n\n\n\n\n\n\n\n\nCountry\nRegion\nState\nPurpose\nds\ny\n\n\n\n\n0\nAustralia\nAdelaide\nSouth Australia\nBusiness\n1998-01-01\n135.077690\n\n\n1\nAustralia\nAdelaide\nSouth Australia\nBusiness\n1998-04-01\n109.987316\n\n\n2\nAustralia\nAdelaide\nSouth Australia\nBusiness\n1998-07-01\n166.034687\n\n\n3\nAustralia\nAdelaide\nSouth Australia\nBusiness\n1998-10-01\n127.160464\n\n\n4\nAustralia\nAdelaide\nSouth Australia\nBusiness\n1999-01-01\n137.448533\n\n\n\n\n\n\n\nThe dataset can be grouped in the following non-strictly hierarchical structure.\n\nspec = [\n ['Country'],\n ['Country', 'State'], \n ['Country', 'Purpose'], \n ['Country', 'State', 'Region'], \n ['Country', 'State', 'Purpose'], \n ['Country', 'State', 'Region', 'Purpose']\n]\n\nUsing the aggregate function from HierarchicalForecast we can generate: 1. Y_df: the hierarchical structured series \\(\\mathbf{y}_{[a,b]\\tau}\\) 2. S_df: the aggregation constraings dataframe with \\(S_{[a,b]}\\) 3. tags: a list with the āunique_idsā conforming each aggregation level.\n\nY_df, S_df, tags = aggregate(df=Y_df, spec=spec)\nY_df = Y_df.reset_index()\n\n/Users/fedex/miniconda3/envs/hierarchicalforecast/lib/python3.10/site-packages/sklearn/preprocessing/_encoders.py:828: FutureWarning: `sparse` was renamed to `sparse_output` in version 1.2 and will be removed in 1.4. `sparse_output` is ignored unless you leave `sparse` to its default value.\n warnings.warn(\n\n\n\nY_df.head()\n\n\n\n\n\n\n\n\nunique_id\nds\ny\n\n\n\n\n0\nAustralia\n1998-01-01\n23182.197269\n\n\n1\nAustralia\n1998-04-01\n20323.380067\n\n\n2\nAustralia\n1998-07-01\n19826.640511\n\n\n3\nAustralia\n1998-10-01\n20830.129891\n\n\n4\nAustralia\n1999-01-01\n22087.353380\n\n\n\n\n\n\n\n\nS_df.iloc[:5, :5]\n\n\n\n\n\n\n\n\nAustralia/ACT/Canberra/Business\nAustralia/ACT/Canberra/Holiday\nAustralia/ACT/Canberra/Other\nAustralia/ACT/Canberra/Visiting\nAustralia/New South Wales/Blue Mountains/Business\n\n\n\n\nAustralia\n1.0\n1.0\n1.0\n1.0\n1.0\n\n\nAustralia/ACT\n1.0\n1.0\n1.0\n1.0\n0.0\n\n\nAustralia/New South Wales\n0.0\n0.0\n0.0\n0.0\n1.0\n\n\nAustralia/Northern Territory\n0.0\n0.0\n0.0\n0.0\n0.0\n\n\nAustralia/Queensland\n0.0\n0.0\n0.0\n0.0\n0.0\n\n\n\n\n\n\n\n\ntags['Country/Purpose']\n\narray(['Australia/Business', 'Australia/Holiday', 'Australia/Other',\n 'Australia/Visiting'], dtype=object)\n\n\nWe can visualize the S_df dataframe and Y_df using the HierarchicalPlot class as follows.\n\nhplot = HierarchicalPlot(S=S_df, tags=tags)\n\n\nhplot.plot_summing_matrix()\n\n\n\n\n\nhplot.plot_hierarchically_linked_series(\n bottom_series='Australia/ACT/Canberra/Holiday',\n Y_df=Y_df.set_index('unique_id')\n)\n\n\n\n\n\nSplit Train/Test sets\nWe use the final two years (8 quarters) as test set.\n\nY_test_df = Y_df.groupby('unique_id').tail(8)\nY_train_df = Y_df.drop(Y_test_df.index)\n\n\nY_test_df = Y_test_df.set_index('unique_id')\nY_train_df = Y_train_df.set_index('unique_id')\n\n\nY_train_df.groupby('unique_id').size()\n\nunique_id\nAustralia 72\nAustralia/ACT 72\nAustralia/ACT/Business 72\nAustralia/ACT/Canberra 72\nAustralia/ACT/Canberra/Business 72\n ..\nAustralia/Western Australia/Experience Perth/Other 72\nAustralia/Western Australia/Experience Perth/Visiting 72\nAustralia/Western Australia/Holiday 72\nAustralia/Western Australia/Other 72\nAustralia/Western Australia/Visiting 72\nLength: 425, dtype: int64" + }, + { + "objectID": "examples/australiandomestictourism-bootstraped-intervals.html#computing-base-forecasts", + "href": "examples/australiandomestictourism-bootstraped-intervals.html#computing-base-forecasts", + "title": "Bootstrap", + "section": "Computing Base Forecasts", + "text": "Computing Base Forecasts\nThe following cell computes the base forecasts for each time series in Y_df using the AutoETS and model. Observe that Y_hat_df contains the forecasts but they are not coherent. Since we are computing prediction intervals using bootstrapping, we only need the fitted values of the models.\n\nfcst = StatsForecast(df=Y_train_df, \n models=[ETS(season_length=4, model='ZAA')],\n freq='QS', n_jobs=-1)\nY_hat_df = fcst.forecast(h=8, fitted=True)\nY_fitted_df = fcst.forecast_fitted_values()\n\n/Users/fedex/miniconda3/envs/hierarchicalforecast/lib/python3.10/site-packages/statsforecast/models.py:526: FutureWarning: `ETS` will be deprecated in future versions of `StatsForecast`. Please use `AutoETS` instead.\n ETS._warn()" + }, + { + "objectID": "examples/australiandomestictourism-bootstraped-intervals.html#reconcile-base-forecasts", + "href": "examples/australiandomestictourism-bootstraped-intervals.html#reconcile-base-forecasts", + "title": "Bootstrap", + "section": "Reconcile Base Forecasts", + "text": "Reconcile Base Forecasts\nThe following cell makes the previous forecasts coherent using the HierarchicalReconciliation class. Since the hierarchy structure is not strict, we canāt use methods such as TopDown or MiddleOut. In this example we use BottomUp and MinTrace. If you want to calculate prediction intervals, you have to use the level argument as follows and set intervals_method='bootstrap'.\n\nreconcilers = [\n BottomUp(),\n MinTrace(method='mint_shrink'),\n MinTrace(method='ols')\n]\nhrec = HierarchicalReconciliation(reconcilers=reconcilers)\nY_rec_df = hrec.reconcile(Y_hat_df=Y_hat_df, Y_df=Y_fitted_df, S=S_df, \n tags=tags, level=[80, 90], \n intervals_method='bootstrap')\n\nThe dataframe Y_rec_df contains the reconciled forecasts.\n\nY_rec_df.head()\n\n\n\n\n\n\n\n\nds\nETS\nETS/BottomUp\nETS/BottomUp-lo-90\nETS/BottomUp-lo-80\nETS/BottomUp-hi-80\nETS/BottomUp-hi-90\nETS/MinTrace_method-mint_shrink\nETS/MinTrace_method-mint_shrink-lo-90\nETS/MinTrace_method-mint_shrink-lo-80\nETS/MinTrace_method-mint_shrink-hi-80\nETS/MinTrace_method-mint_shrink-hi-90\nETS/MinTrace_method-ols\nETS/MinTrace_method-ols-lo-90\nETS/MinTrace_method-ols-lo-80\nETS/MinTrace_method-ols-hi-80\nETS/MinTrace_method-ols-hi-90\n\n\nunique_id\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nAustralia\n2016-01-01\n26080.878906\n24487.349609\n23244.120996\n23333.694727\n25381.792969\n25426.333984\n25532.523559\n24428.911701\n24709.210638\n26365.606934\n26476.255501\n26034.114241\n24914.136375\n25100.462938\n27102.735022\n27176.416922\n\n\nAustralia\n2016-04-01\n24587.011719\n23069.744141\n21826.519434\n21912.962891\n23946.606250\n24281.447266\n24118.557177\n23199.968626\n23295.244252\n25108.470410\n25489.383606\n24567.460995\n23484.050568\n23640.638423\n25709.763678\n25809.249492\n\n\nAustralia\n2016-07-01\n24147.308594\n22689.777344\n21297.136719\n21530.438281\n23701.173828\n24155.820312\n23731.251387\n22627.639669\n22818.729182\n24821.488458\n25246.867432\n24150.134898\n23030.156834\n23155.025556\n25359.992376\n25404.841402\n\n\nAustralia\n2016-10-01\n24794.041016\n23429.757812\n22037.123047\n22276.453125\n24241.417969\n24441.160156\n24486.549344\n23385.927232\n23600.704525\n25353.555625\n25481.478557\n24831.584516\n23725.924464\n23836.475174\n25900.205254\n25977.265089\n\n\nAustralia\n2017-01-01\n26284.000000\n24940.042969\n23696.722754\n23904.382812\n25814.941406\n25974.169922\n26041.867488\n24972.077858\n25158.986710\n26918.104747\n27135.580845\n26348.203335\n25254.659324\n25487.502291\n27410.873035\n27477.334507" + }, + { + "objectID": "examples/australiandomestictourism-bootstraped-intervals.html#plot-predictions", + "href": "examples/australiandomestictourism-bootstraped-intervals.html#plot-predictions", + "title": "Bootstrap", + "section": "Plot Predictions", + "text": "Plot Predictions\nThen we can plot the probabilist forecasts using the following function.\n\nplot_df = pd.concat([Y_df.set_index(['unique_id', 'ds']), \n Y_rec_df.set_index('ds', append=True)], axis=1)\nplot_df = plot_df.reset_index('ds')\n\n\nPlot single time series\n\nhplot.plot_series(\n series='Australia',\n Y_df=plot_df, \n models=['y', 'ETS', 'ETS/MinTrace_method-ols', 'ETS/MinTrace_method-mint_shrink'],\n level=[80]\n)\n\n\n\n\n\n# Since we are plotting a bottom time series\n# the probabilistic and mean forecasts\n# differ due to bootstrapping\nhplot.plot_series(\n series='Australia/Western Australia/Experience Perth/Visiting',\n Y_df=plot_df, \n models=['y', 'ETS', 'ETS/BottomUp'],\n level=[80]\n)\n\n\n\n\n\n\nPlot hierarchichally linked time series\n\nhplot.plot_hierarchically_linked_series(\n bottom_series='Australia/Western Australia/Experience Perth/Visiting',\n Y_df=plot_df, \n models=['y', 'ETS', 'ETS/MinTrace_method-ols', 'ETS/BottomUp'],\n level=[80]\n)\n\n\n\n\n\n# ACT only has Canberra\nhplot.plot_hierarchically_linked_series(\n bottom_series='Australia/ACT/Canberra/Other',\n Y_df=plot_df, \n models=['y', 'ETS/MinTrace_method-mint_shrink'],\n level=[80, 90]\n)\n\n\n\n\n\n\nReferences\n\nHyndman, R.J., & Athanasopoulos, G. (2021). āForecasting: principles and practice, 3rd edition: Chapter 11: Forecasting hierarchical and grouped series.ā. OTexts: Melbourne, Australia. OTexts.com/fpp3 Accessed on July 2022.\nShanika L. Wickramasuriya, George Athanasopoulos, and Rob J. Hyndman. Optimal forecast reconciliation for hierarchical and grouped time series through trace minimization.Journal of the American Statistical Association, 114(526):804ā819, 2019. doi: 10.1080/01621459.2018.1448825. URL https://robjhyndman.com/publications/mint/.\nPuwasala Gamakumara Ph. D. dissertation. Monash University, Econometrics and Business Statistics (2020). āProbabilistic Forecast Reconciliationā" + }, + { + "objectID": "examples/australiandomestictourism-permbu-intervals.html", + "href": "examples/australiandomestictourism-permbu-intervals.html", + "title": "PERMBU", + "section": "", + "text": "In many cases, only the time series at the lowest level of the hierarchies (bottom time series) are available. HierarchicalForecast has tools to create time series for all hierarchies and also allows you to calculate prediction intervals for all hierarchies. In this notebook we will see how to do it.\n!pip install hierarchicalforecast statsforecast\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\n\n# compute base forecast no coherent\nfrom statsforecast.models import AutoARIMA\nfrom statsforecast.core import StatsForecast\n\n#obtain hierarchical reconciliation methods and evaluation\nfrom hierarchicalforecast.methods import BottomUp, MinTrace\nfrom hierarchicalforecast.utils import aggregate, HierarchicalPlot\nfrom hierarchicalforecast.core import HierarchicalReconciliation\nfrom hierarchicalforecast.evaluation import HierarchicalEvaluation\n\n/Users/fedex/miniconda3/envs/hierarchicalforecast/lib/python3.10/site-packages/statsforecast/core.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n from tqdm.autonotebook import tqdm\nIf you find the code useful, please ā us on Github" + }, + { + "objectID": "examples/australiandomestictourism-permbu-intervals.html#aggregate-bottom-time-series", + "href": "examples/australiandomestictourism-permbu-intervals.html#aggregate-bottom-time-series", + "title": "PERMBU", + "section": "Aggregate bottom time series", + "text": "Aggregate bottom time series\nIn this example we will use the Tourism dataset from the Forecasting: Principles and Practice book. The dataset only contains the time series at the lowest level, so we need to create the time series for all hierarchies.\n\nY_df = pd.read_csv('https://raw.githubusercontent.com/Nixtla/transfer-learning-time-series/main/datasets/tourism.csv')\nY_df = Y_df.rename({'Trips': 'y', 'Quarter': 'ds'}, axis=1)\nY_df.insert(0, 'Country', 'Australia')\nY_df = Y_df[['Country', 'Region', 'State', 'Purpose', 'ds', 'y']]\nY_df['ds'] = Y_df['ds'].str.replace(r'(\\d+) (Q\\d)', r'\\1-\\2', regex=True)\nY_df['ds'] = pd.to_datetime(Y_df['ds'])\nY_df.head()\n\n\n\n\n\n\n\n\nCountry\nRegion\nState\nPurpose\nds\ny\n\n\n\n\n0\nAustralia\nAdelaide\nSouth Australia\nBusiness\n1998-01-01\n135.077690\n\n\n1\nAustralia\nAdelaide\nSouth Australia\nBusiness\n1998-04-01\n109.987316\n\n\n2\nAustralia\nAdelaide\nSouth Australia\nBusiness\n1998-07-01\n166.034687\n\n\n3\nAustralia\nAdelaide\nSouth Australia\nBusiness\n1998-10-01\n127.160464\n\n\n4\nAustralia\nAdelaide\nSouth Australia\nBusiness\n1999-01-01\n137.448533\n\n\n\n\n\n\n\nThe dataset can be grouped in the following strictly hierarchical structure.\n\nspec = [\n ['Country'],\n ['Country', 'State'], \n ['Country', 'State', 'Region']\n]\n\nUsing the aggregate function from HierarchicalForecast we can get the full set of time series.\n\nY_df, S_df, tags = aggregate(df=Y_df, spec=spec)\nY_df = Y_df.reset_index()\n\n/Users/fedex/miniconda3/envs/hierarchicalforecast/lib/python3.10/site-packages/sklearn/preprocessing/_encoders.py:828: FutureWarning: `sparse` was renamed to `sparse_output` in version 1.2 and will be removed in 1.4. `sparse_output` is ignored unless you leave `sparse` to its default value.\n warnings.warn(\n\n\n\nY_df.head()\n\n\n\n\n\n\n\n\nunique_id\nds\ny\n\n\n\n\n0\nAustralia\n1998-01-01\n23182.197269\n\n\n1\nAustralia\n1998-04-01\n20323.380067\n\n\n2\nAustralia\n1998-07-01\n19826.640511\n\n\n3\nAustralia\n1998-10-01\n20830.129891\n\n\n4\nAustralia\n1999-01-01\n22087.353380\n\n\n\n\n\n\n\n\nS_df.iloc[:5, :5]\n\n\n\n\n\n\n\n\nAustralia/ACT/Canberra\nAustralia/New South Wales/Blue Mountains\nAustralia/New South Wales/Capital Country\nAustralia/New South Wales/Central Coast\nAustralia/New South Wales/Central NSW\n\n\n\n\nAustralia\n1.0\n1.0\n1.0\n1.0\n1.0\n\n\nAustralia/ACT\n1.0\n0.0\n0.0\n0.0\n0.0\n\n\nAustralia/New South Wales\n0.0\n1.0\n1.0\n1.0\n1.0\n\n\nAustralia/Northern Territory\n0.0\n0.0\n0.0\n0.0\n0.0\n\n\nAustralia/Queensland\n0.0\n0.0\n0.0\n0.0\n0.0\n\n\n\n\n\n\n\n\ntags['Country/State']\n\narray(['Australia/ACT', 'Australia/New South Wales',\n 'Australia/Northern Territory', 'Australia/Queensland',\n 'Australia/South Australia', 'Australia/Tasmania',\n 'Australia/Victoria', 'Australia/Western Australia'], dtype=object)\n\n\nWe can visualize the S matrix and the data using the HierarchicalPlot class as follows.\n\nhplot = HierarchicalPlot(S=S_df, tags=tags)\n\n\nhplot.plot_summing_matrix()\n\n\n\n\n\nhplot.plot_hierarchically_linked_series(\n bottom_series='Australia/ACT/Canberra',\n Y_df=Y_df.set_index('unique_id')\n)\n\n\n\n\n\nSplit Train/Test sets\nWe use the final two years (8 quarters) as test set.\n\nY_test_df = Y_df.groupby('unique_id').tail(8)\nY_train_df = Y_df.drop(Y_test_df.index)\n\n\nY_test_df = Y_test_df.set_index('unique_id')\nY_train_df = Y_train_df.set_index('unique_id')\n\n\nY_train_df.groupby('unique_id').size()\n\nunique_id\nAustralia 72\nAustralia/ACT 72\nAustralia/ACT/Canberra 72\nAustralia/New South Wales 72\nAustralia/New South Wales/Blue Mountains 72\n ..\nAustralia/Western Australia/Australia's Coral Coast 72\nAustralia/Western Australia/Australia's Golden Outback 72\nAustralia/Western Australia/Australia's North West 72\nAustralia/Western Australia/Australia's South West 72\nAustralia/Western Australia/Experience Perth 72\nLength: 85, dtype: int64" + }, + { + "objectID": "examples/australiandomestictourism-permbu-intervals.html#computing-base-forecasts", + "href": "examples/australiandomestictourism-permbu-intervals.html#computing-base-forecasts", + "title": "PERMBU", + "section": "Computing base forecasts", + "text": "Computing base forecasts\nThe following cell computes the base forecasts for each time series in Y_df using the AutoARIMA and model. Observe that Y_hat_df contains the forecasts but they are not coherent. To reconcile the prediction intervals we need to calculate the uncoherent intervals using the level argument of StatsForecast.\n\nfcst = StatsForecast(df=Y_train_df,\n models=[AutoARIMA(season_length=4)], \n freq='QS', n_jobs=-1)\nY_hat_df = fcst.forecast(h=8, fitted=True, level=[80, 90])\nY_fitted_df = fcst.forecast_fitted_values()" + }, + { + "objectID": "examples/australiandomestictourism-permbu-intervals.html#reconcile-forecasts-and-compute-prediction-intervals-using-permbu", + "href": "examples/australiandomestictourism-permbu-intervals.html#reconcile-forecasts-and-compute-prediction-intervals-using-permbu", + "title": "PERMBU", + "section": "Reconcile forecasts and compute prediction intervals using PERMBU", + "text": "Reconcile forecasts and compute prediction intervals using PERMBU\nThe following cell makes the previous forecasts coherent using the HierarchicalReconciliation class. In this example we use BottomUp and MinTrace. If you want to calculate prediction intervals, you have to use the level argument as follows and also intervals_method='permbu'.\n\nreconcilers = [\n BottomUp(),\n MinTrace(method='mint_shrink'),\n MinTrace(method='ols')\n]\nhrec = HierarchicalReconciliation(reconcilers=reconcilers)\nY_rec_df = hrec.reconcile(Y_hat_df=Y_hat_df, Y_df=Y_fitted_df,\n S=S_df, tags=tags,\n level=[80, 90], intervals_method='permbu')\n\n/Users/fedex/miniconda3/envs/hierarchicalforecast/lib/python3.10/site-packages/sklearn/preprocessing/_encoders.py:828: FutureWarning: `sparse` was renamed to `sparse_output` in version 1.2 and will be removed in 1.4. `sparse_output` is ignored unless you leave `sparse` to its default value.\n warnings.warn(\n/Users/fedex/miniconda3/envs/hierarchicalforecast/lib/python3.10/site-packages/sklearn/preprocessing/_encoders.py:828: FutureWarning: `sparse` was renamed to `sparse_output` in version 1.2 and will be removed in 1.4. `sparse_output` is ignored unless you leave `sparse` to its default value.\n warnings.warn(\n/Users/fedex/miniconda3/envs/hierarchicalforecast/lib/python3.10/site-packages/sklearn/preprocessing/_encoders.py:828: FutureWarning: `sparse` was renamed to `sparse_output` in version 1.2 and will be removed in 1.4. `sparse_output` is ignored unless you leave `sparse` to its default value.\n warnings.warn(\n/Users/fedex/miniconda3/envs/hierarchicalforecast/lib/python3.10/site-packages/sklearn/preprocessing/_encoders.py:828: FutureWarning: `sparse` was renamed to `sparse_output` in version 1.2 and will be removed in 1.4. `sparse_output` is ignored unless you leave `sparse` to its default value.\n warnings.warn(\n/Users/fedex/miniconda3/envs/hierarchicalforecast/lib/python3.10/site-packages/sklearn/preprocessing/_encoders.py:828: FutureWarning: `sparse` was renamed to `sparse_output` in version 1.2 and will be removed in 1.4. `sparse_output` is ignored unless you leave `sparse` to its default value.\n warnings.warn(\n/Users/fedex/miniconda3/envs/hierarchicalforecast/lib/python3.10/site-packages/sklearn/preprocessing/_encoders.py:828: FutureWarning: `sparse` was renamed to `sparse_output` in version 1.2 and will be removed in 1.4. `sparse_output` is ignored unless you leave `sparse` to its default value.\n warnings.warn(\n\n\nThe dataframe Y_rec_df contains the reconciled forecasts.\n\nY_rec_df.head()\n\n\n\n\n\n\n\n\nds\nAutoARIMA\nAutoARIMA-lo-90\nAutoARIMA-lo-80\nAutoARIMA-hi-80\nAutoARIMA-hi-90\nAutoARIMA/BottomUp\nAutoARIMA/BottomUp-lo-90\nAutoARIMA/BottomUp-lo-80\nAutoARIMA/BottomUp-hi-80\n...\nAutoARIMA/MinTrace_method-mint_shrink\nAutoARIMA/MinTrace_method-mint_shrink-lo-90\nAutoARIMA/MinTrace_method-mint_shrink-lo-80\nAutoARIMA/MinTrace_method-mint_shrink-hi-80\nAutoARIMA/MinTrace_method-mint_shrink-hi-90\nAutoARIMA/MinTrace_method-ols\nAutoARIMA/MinTrace_method-ols-lo-90\nAutoARIMA/MinTrace_method-ols-lo-80\nAutoARIMA/MinTrace_method-ols-hi-80\nAutoARIMA/MinTrace_method-ols-hi-90\n\n\nunique_id\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nAustralia\n2016-01-01\n26212.554688\n24694.224609\n25029.580078\n27395.527344\n27730.884766\n24865.636719\n24106.802510\n24373.962043\n25423.566450\n...\n25395.411928\n24733.046633\n24824.274681\n25939.345007\n25998.692460\n26133.758953\n25516.484518\n25600.644926\n26662.923204\n26855.585562\n\n\nAustralia\n2016-04-01\n25033.667969\n23324.066406\n23701.669922\n26365.666016\n26743.269531\n23247.097656\n22696.597930\n22821.256357\n23830.632567\n...\n23986.272540\n23289.811432\n23525.630785\n24563.998645\n24739.826238\n24934.260399\n24402.570904\n24481.968560\n25567.085565\n25696.312229\n\n\nAustralia\n2016-07-01\n24507.027344\n22625.500000\n23041.076172\n25972.978516\n26388.554688\n22658.207031\n21816.988906\n22011.905035\n23158.311619\n...\n23345.821184\n22688.605574\n22780.602574\n23934.244609\n24033.906220\n24374.026569\n23539.673724\n23797.836651\n24893.463090\n25098.321828\n\n\nAustralia\n2016-10-01\n25598.929688\n23559.919922\n24010.281250\n27187.578125\n27637.937500\n23330.804688\n22567.948299\n22694.449708\n23850.068162\n...\n24275.423420\n23392.040447\n23626.165662\n24828.207813\n24958.926002\n25477.951913\n24793.436993\n24911.271547\n26006.244161\n26152.362329\n\n\nAustralia\n2017-01-01\n26982.578125\n24651.535156\n25166.396484\n28798.757812\n29313.619141\n24497.001953\n23578.418503\n23731.657437\n25114.564017\n...\n25485.433879\n24549.969625\n24802.819691\n26073.792872\n26284.826386\n26842.564741\n26037.725561\n26248.171831\n27436.222761\n27668.067666\n\n\n\n\n5 rows Ć 21 columns" + }, + { + "objectID": "examples/australiandomestictourism-permbu-intervals.html#plot-forecasts", + "href": "examples/australiandomestictourism-permbu-intervals.html#plot-forecasts", + "title": "PERMBU", + "section": "Plot forecasts", + "text": "Plot forecasts\nThen we can plot the probabilist forecasts using the following function.\n\nplot_df = pd.concat([Y_df.set_index(['unique_id', 'ds']), \n Y_rec_df.set_index('ds', append=True)], axis=1)\nplot_df = plot_df.reset_index('ds')\n\n\nPlot single time series\n\nhplot.plot_series(\n series='Australia',\n Y_df=plot_df, \n models=['y', 'AutoARIMA', \n 'AutoARIMA/MinTrace_method-ols',\n 'AutoARIMA/BottomUp'\n ],\n level=[80]\n)\n\n\n\n\n\n\nPlot hierarchichally linked time series\n\nhplot.plot_hierarchically_linked_series(\n bottom_series='Australia/Western Australia/Experience Perth',\n Y_df=plot_df, \n models=['y', 'AutoARIMA', 'AutoARIMA/MinTrace_method-ols', 'AutoARIMA/BottomUp'],\n level=[80]\n)\n\n\n\n\n\n# ACT only has Canberra\nhplot.plot_hierarchically_linked_series(\n bottom_series='Australia/ACT/Canberra',\n Y_df=plot_df, \n models=['y', 'AutoARIMA/MinTrace_method-mint_shrink'],\n level=[80, 90]\n)\n\n\n\n\n\n\nReferences\n\nHyndman, R.J., & Athanasopoulos, G. (2021). āForecasting: principles and practice, 3rd edition: Chapter 11: Forecasting hierarchical and grouped series.ā. OTexts: Melbourne, Australia. OTexts.com/fpp3 Accessed on July 2022.\nShanika L. Wickramasuriya, George Athanasopoulos, and Rob J. Hyndman. Optimal forecast reconciliation for hierarchical and grouped time series through trace minimization.Journal of the American Statistical Association, 114(526):804ā819, 2019. doi: 10.1080/01621459.2018.1448825. URL https://robjhyndman.com/publications/mint/." + }, + { + "objectID": "examples/hierarchicalforecast-gluonts.html", + "href": "examples/hierarchicalforecast-gluonts.html", + "title": "GluonTS", + "section": "", + "text": "This example notebook demonstrates the compatibility of HierarchicalForecastās reconciliation methods with popular machine-learning libraries, specifically GluonTS.\nThe notebook utilizes the GluonTS DeepAREstimator to create base forecasts for the TourismLarge Hierarchical Dataset. We make the base forecasts compatible with HierarchicalForecastās reconciliation functions via the samples_to_quantiles_df utility function that transforms GluonTSā output forecasts into a compatible data frame format. After that, we use HierarchicalForecast to reconcile the base predictions.\nReferences - David Salinas, Valentin Flunkert, Jan Gasthaus, Tim Januschowski (2020). āDeepAR: Probabilistic forecasting with autoregressive recurrent networksā. International Journal of Forecasting. - Alexander Alexandrov et. al (2020). āGluonTS: Probabilistic and Neural Time Series Modeling in Pythonā. Journal of Machine Learning Research.\nYou can run these experiments using CPU or GPU with Google Colab.\nIf you find the code useful, please ā us on Github" + }, + { + "objectID": "examples/hierarchicalforecast-gluonts.html#installing-packages", + "href": "examples/hierarchicalforecast-gluonts.html#installing-packages", + "title": "GluonTS", + "section": "1. Installing packages", + "text": "1. Installing packages\n\n!pip install mxnet-cu112\n\n\nimport mxnet as mx\n\nassert mx.context.num_gpus()>0\n\n\n!pip install gluonts\n!pip install datasetsforecast\n!pip install git+https://github.com/Nixtla/hierarchicalforecast.git\n\n\nimport numpy as np\nimport pandas as pd\n\nfrom datasetsforecast.hierarchical import HierarchicalData\n\nfrom gluonts.mx.trainer import Trainer\nfrom gluonts.dataset.pandas import PandasDataset\nfrom gluonts.mx.model.deepar import DeepAREstimator\n\nfrom hierarchicalforecast.methods import BottomUp, MinTrace\nfrom hierarchicalforecast.core import HierarchicalReconciliation\nfrom hierarchicalforecast.evaluation import scaled_crps\nfrom hierarchicalforecast.utils import samples_to_quantiles_df\n\n/usr/local/lib/python3.10/dist-packages/gluonts/json.py:101: UserWarning: Using `json`-module for json-handling. Consider installing one of `orjson`, `ujson` to speed up serialization and deserialization.\n warnings.warn(" + }, + { + "objectID": "examples/hierarchicalforecast-gluonts.html#load-hierarchical-dataset", + "href": "examples/hierarchicalforecast-gluonts.html#load-hierarchical-dataset", + "title": "GluonTS", + "section": "2. Load hierarchical dataset", + "text": "2. Load hierarchical dataset\nThis detailed Australian Tourism Dataset comes from the National Visitor Survey, managed by the Tourism Research Australia, it is composed of 555 monthly series from 1998 to 2016, it is organized geographically, and purpose of travel. The natural geographical hierarchy comprises seven states, divided further in 27 zones and 76 regions. The purpose of travel categories are holiday, visiting friends and relatives (VFR), business and other. The MinT (Wickramasuriya et al., 2019), among other hierarchical forecasting studies has used the dataset it in the past. The dataset can be accessed in the MinT reconciliation webpage, although other sources are available.\n\n\n\n\n\n\n\n\n\nGeographical Division\nNumber of series per division\nNumber of series per purpose\nTotal\n\n\n\n\nAustralia\n1\n4\n5\n\n\nStates\n7\n28\n35\n\n\nZones\n27\n108\n135\n\n\nRegions\n76\n304\n380\n\n\nTotal\n111\n444\n555\n\n\n\n\ndataset = 'TourismLarge'\nY_df, S_df, tags = HierarchicalData.load(directory = \"./data\", group=dataset)\nY_df['ds'] = pd.to_datetime(Y_df['ds'])\n\n\ndef sort_hier_df(Y_df, S_df):\n # sorts unique_id lexicographically\n Y_df.unique_id = Y_df.unique_id.astype('category')\n Y_df.unique_id = Y_df.unique_id.cat.set_categories(S_df.index)\n Y_df = Y_df.sort_values(by=['unique_id', 'ds'])\n return Y_df\n\nY_df = sort_hier_df(Y_df, S_df)\n\n\nhorizon = 12\n\nY_test_df = Y_df.groupby('unique_id').tail(horizon)\nY_train_df = Y_df.drop(Y_test_df.index)\nY_train_df\n\n\n \n \n \n\n\n\n\n\n\nunique_id\nds\ny\n\n\n\n\n0\nTotalAll\n1998-01-01\n45151.071280\n\n\n1\nTotalAll\n1998-02-01\n17294.699551\n\n\n2\nTotalAll\n1998-03-01\n20725.114184\n\n\n3\nTotalAll\n1998-04-01\n25388.612353\n\n\n4\nTotalAll\n1998-05-01\n20330.035211\n\n\n...\n...\n...\n...\n\n\n126523\nGBDOth\n2015-08-01\n17.683774\n\n\n126524\nGBDOth\n2015-09-01\n0.000000\n\n\n126525\nGBDOth\n2015-10-01\n0.000000\n\n\n126526\nGBDOth\n2015-11-01\n0.000000\n\n\n126527\nGBDOth\n2015-12-01\n0.000000\n\n\n\n\n\n119880 rows Ć 3 columns\n\n \n \n \n \n \n \n \n \n \n\n \n \n \n \n\n\n\nds = PandasDataset.from_long_dataframe(Y_train_df, target=\"y\", item_id=\"unique_id\")" + }, + { + "objectID": "examples/hierarchicalforecast-gluonts.html#fit-and-predict-model", + "href": "examples/hierarchicalforecast-gluonts.html#fit-and-predict-model", + "title": "GluonTS", + "section": "3. Fit and Predict Model", + "text": "3. Fit and Predict Model\n\nestimator = DeepAREstimator(\n freq=\"M\",\n prediction_length=horizon,\n trainer=Trainer(ctx = mx.context.gpu(),\n epochs=20),\n)\npredictor = estimator.train(ds)\n\nforecast_it = predictor.predict(ds, num_samples=1000)\n\nforecasts = list(forecast_it)\nforecasts = np.array([arr.samples for arr in forecasts])\nforecasts.shape\n\n100%|āāāāāāāāāā| 50/50 [00:11<00:00, 4.39it/s, epoch=1/20, avg_epoch_loss=5.35]\n100%|āāāāāāāāāā| 50/50 [00:05<00:00, 8.75it/s, epoch=2/20, avg_epoch_loss=5.22]\n100%|āāāāāāāāāā| 50/50 [00:03<00:00, 14.41it/s, epoch=3/20, avg_epoch_loss=5.17]\n100%|āāāāāāāāāā| 50/50 [00:02<00:00, 20.76it/s, epoch=4/20, avg_epoch_loss=5.02]\n100%|āāāāāāāāāā| 50/50 [00:02<00:00, 19.27it/s, epoch=5/20, avg_epoch_loss=5.05]\n100%|āāāāāāāāāā| 50/50 [00:04<00:00, 11.52it/s, epoch=6/20, avg_epoch_loss=5.12]\n100%|āāāāāāāāāā| 50/50 [00:03<00:00, 16.59it/s, epoch=7/20, avg_epoch_loss=4.97]\n100%|āāāāāāāāāā| 50/50 [00:03<00:00, 16.27it/s, epoch=8/20, avg_epoch_loss=4.97]\n100%|āāāāāāāāāā| 50/50 [00:02<00:00, 19.96it/s, epoch=9/20, avg_epoch_loss=5.11]\n100%|āāāāāāāāāā| 50/50 [00:04<00:00, 11.36it/s, epoch=10/20, avg_epoch_loss=4.97]\n100%|āāāāāāāāāā| 50/50 [00:03<00:00, 16.62it/s, epoch=11/20, avg_epoch_loss=5.05]\n100%|āāāāāāāāāā| 50/50 [00:02<00:00, 17.76it/s, epoch=12/20, avg_epoch_loss=5.04]\n100%|āāāāāāāāāā| 50/50 [00:02<00:00, 21.56it/s, epoch=13/20, avg_epoch_loss=4.99]\n100%|āāāāāāāāāā| 50/50 [00:02<00:00, 20.64it/s, epoch=14/20, avg_epoch_loss=5.03]\n100%|āāāāāāāāāā| 50/50 [00:03<00:00, 13.22it/s, epoch=15/20, avg_epoch_loss=4.97]\n100%|āāāāāāāāāā| 50/50 [00:02<00:00, 17.79it/s, epoch=16/20, avg_epoch_loss=4.95]\n100%|āāāāāāāāāā| 50/50 [00:02<00:00, 18.29it/s, epoch=17/20, avg_epoch_loss=5.02]\n100%|āāāāāāāāāā| 50/50 [00:02<00:00, 17.73it/s, epoch=18/20, avg_epoch_loss=5.02]\n100%|āāāāāāāāāā| 50/50 [00:02<00:00, 19.10it/s, epoch=19/20, avg_epoch_loss=5.02]\n100%|āāāāāāāāāā| 50/50 [00:03<00:00, 13.29it/s, epoch=20/20, avg_epoch_loss=5]\n\n\n(555, 1000, 12)" + }, + { + "objectID": "examples/hierarchicalforecast-gluonts.html#reconciliation", + "href": "examples/hierarchicalforecast-gluonts.html#reconciliation", + "title": "GluonTS", + "section": "4. Reconciliation", + "text": "4. Reconciliation\n\nlevel = np.arange(1, 100, 2)\n\n#transform the output of DeepAREstimator to a form that is compatible with HierarchicalForecast\nquantiles, forecast_df = samples_to_quantiles_df(samples=forecasts, \n unique_ids=S_df.index, \n dates=Y_test_df['ds'].unique(), \n level=level,\n model_name='DeepAREstimator')\n\n#reconcile forecasts\nreconcilers = [\n BottomUp(),\n MinTrace('ols')\n]\nhrec = HierarchicalReconciliation(reconcilers=reconcilers)\n\nforecast_rec = hrec.reconcile(Y_hat_df=forecast_df, S=S_df, tags=tags, level=level)\n\n\nforecast_rec\n\n\n \n \n \n\n\n\n\n\n\nds\nDeepAREstimator\nDeepAREstimator-median\nDeepAREstimator-lo-99\nDeepAREstimator-lo-97\nDeepAREstimator-lo-95\nDeepAREstimator-lo-93\nDeepAREstimator-lo-91\nDeepAREstimator-lo-89\nDeepAREstimator-lo-87\n...\nDeepAREstimator/MinTrace_method-ols-hi-81\nDeepAREstimator/MinTrace_method-ols-hi-83\nDeepAREstimator/MinTrace_method-ols-hi-85\nDeepAREstimator/MinTrace_method-ols-hi-87\nDeepAREstimator/MinTrace_method-ols-hi-89\nDeepAREstimator/MinTrace_method-ols-hi-91\nDeepAREstimator/MinTrace_method-ols-hi-93\nDeepAREstimator/MinTrace_method-ols-hi-95\nDeepAREstimator/MinTrace_method-ols-hi-97\nDeepAREstimator/MinTrace_method-ols-hi-99\n\n\nunique_id\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\nTotalAll\n2016-01-01\n43165.929688\n43002.058594\n27712.297979\n30371.243516\n32741.458740\n33305.429492\n34446.465957\n35164.380410\n35732.592422\n...\n48703.132046\n48956.752480\n49233.843836\n49540.743219\n49886.826218\n50286.877928\n50766.394577\n51375.717577\n52240.506366\n53910.351214\n\n\nTotalAll\n2016-02-01\n20326.796875\n20469.210938\n13156.550879\n15086.488257\n15738.457031\n16134.386343\n16696.160010\n16828.676436\n17139.442129\n...\n22902.635244\n23019.412684\n23146.997118\n23288.306411\n23447.657478\n23631.857993\n23852.647485\n24133.205242\n24531.390118\n25300.256426\n\n\nTotalAll\n2016-03-01\n24362.203125\n24237.250977\n17340.837197\n18470.071582\n19132.180615\n19658.168945\n19974.223359\n20339.483584\n20519.382959\n...\n26759.166634\n26873.896338\n26999.243530\n27138.074912\n27294.631699\n27475.602189\n27692.520055\n27968.158127\n28359.360682\n29114.744632\n\n\nTotalAll\n2016-04-01\n29131.662109\n29236.008789\n19923.623740\n21814.112246\n22685.987500\n23350.113418\n23721.056963\n24168.286201\n24513.198066\n...\n32277.209370\n32427.584386\n32591.875632\n32773.840464\n32979.037796\n33216.233913\n33500.545877\n33861.821798\n34374.566871\n35364.640665\n\n\nTotalAll\n2016-05-01\n22587.779297\n22638.541016\n14453.285947\n16236.985869\n17163.251807\n17894.046758\n18559.204453\n18789.053066\n19055.381455\n...\n25400.976716\n25532.984575\n25677.208902\n25836.948122\n26017.082170\n26225.306596\n26474.892029\n26792.040860\n27242.158045\n28111.301901\n\n\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n...\n\n\nGBDOth\n2016-08-01\n-0.300811\n-0.316894\n-2.994549\n-2.208182\n-2.005075\n-1.725068\n-1.620723\n-1.501304\n-1.355108\n...\n27.151595\n28.293141\n29.540330\n30.921685\n32.479405\n34.280039\n36.438344\n39.180908\n43.073324\n50.589300\n\n\nGBDOth\n2016-09-01\n-0.089410\n-0.079164\n-2.981229\n-2.356738\n-1.812428\n-1.499515\n-1.365453\n-1.199702\n-1.120727\n...\n24.912080\n26.035044\n27.261932\n28.620801\n30.153165\n31.924489\n34.047662\n36.745584\n40.574640\n47.968273\n\n\nGBDOth\n2016-10-01\n-0.196041\n-0.207104\n-2.829650\n-2.270969\n-1.674091\n-1.289834\n-1.153728\n-1.078916\n-1.029915\n...\n25.423958\n26.550973\n27.782287\n29.146059\n30.683952\n32.461666\n34.592499\n37.300154\n41.143025\n48.563331\n\n\nGBDOth\n2016-11-01\n-0.315826\n-0.274183\n-2.461571\n-1.829249\n-1.535889\n-1.329642\n-1.260961\n-1.134465\n-1.007276\n...\n25.125960\n26.257991\n27.494784\n28.864625\n30.409361\n32.194986\n34.335301\n37.055005\n40.914977\n48.368305\n\n\nGBDOth\n2016-12-01\n-0.291579\n-0.268462\n-3.987842\n-2.078746\n-1.619226\n-1.385310\n-1.253607\n-1.156472\n-1.092625\n...\n26.216098\n27.310535\n28.506255\n29.830604\n31.324041\n33.050366\n35.119603\n37.748987\n41.480772\n48.686579\n\n\n\n\n\n6660 rows Ć 305 columns" + }, + { + "objectID": "examples/hierarchicalforecast-gluonts.html#evaluation", + "href": "examples/hierarchicalforecast-gluonts.html#evaluation", + "title": "GluonTS", + "section": "5. Evaluation", + "text": "5. Evaluation\nTo evaluate we use a scaled variation of the CRPS, as proposed by Rangapuram (2021), to measure the accuracy of predicted quantiles y_hat compared to the observation y.\n\\[ \\mathrm{sCRPS}(\\hat{F}_{\\tau}, \\mathbf{y}_{\\tau}) = \\frac{2}{N} \\sum_{i}\n\\int^{1}_{0}\n\\frac{\\mathrm{QL}(\\hat{F}_{i,\\tau}, y_{i,\\tau})_{q}}{\\sum_{i} | y_{i,\\tau} |} dq \\]\nAs you can see, HierarchicalForecast results improve on the results of specialized algorithms like HierE2E.\n\nrec_model_names = ['DeepAREstimator/MinTrace_method-ols', 'DeepAREstimator/BottomUp']\n\nquantiles = np.array(quantiles[1:]) #remove first quantile (median)\nn_quantiles = len(quantiles)\nn_series = len(S_df)\n\nfor name in rec_model_names:\n quantile_columns = [col for col in forecast_rec.columns if (name+'-') in col]\n y_rec = forecast_rec[quantile_columns].values \n y_test = Y_test_df['y'].values\n\n y_rec = y_rec.reshape(n_series, horizon, n_quantiles)\n y_test = y_test.reshape(n_series, horizon)\n scrps = scaled_crps(y=y_test, y_hat=y_rec, quantiles=quantiles)\n print(\"{:<40} {:.5f}\".format(name+\":\", scrps))\n\nDeepAREstimator/MinTrace_method-ols: 0.12632\nDeepAREstimator/BottomUp: 0.13933" + }, + { + "objectID": "examples/tourismsmall.html", + "href": "examples/tourismsmall.html", + "title": "Reconciliation Quick Start", + "section": "", + "text": "Large collections of time series organized into structures at different aggregation levels often require their forecasts to follow their aggregation constraints, which poses the challenge of creating novel algorithms capable of coherent forecasts.\nThe HierarchicalForecast package provides a wide collection of Python implementations of hierarchical forecasting algorithms that follow classic hierarchical reconciliation.\nIn this notebook we will show how to use the StatsForecast library to produce base forecasts, and use HierarchicalForecast package to perform hierarchical reconciliation.\nYou can run these experiments using CPU or GPU with Google Colab.\nIf you find the code useful, please ā us on Github" + }, + { + "objectID": "examples/tourismsmall.html#libraries", + "href": "examples/tourismsmall.html#libraries", + "title": "Reconciliation Quick Start", + "section": "1. Libraries", + "text": "1. Libraries\n\n!pip install hierarchicalforecast\n!pip install -U numba statsforecast datasetsforecast" + }, + { + "objectID": "examples/tourismsmall.html#load-data", + "href": "examples/tourismsmall.html#load-data", + "title": "Reconciliation Quick Start", + "section": "2. Load Data", + "text": "2. Load Data\nIn this example we will use the TourismSmall dataset. The following cell gets the time series for the different levels in the hierarchy, the summing matrix S which recovers the full dataset from the bottom level hierarchy and the indices of each hierarchy denoted by tags.\n\nimport numpy as np\nimport pandas as pd\n\nfrom datasetsforecast.hierarchical import HierarchicalData\n\n\nY_df, S_df, tags = HierarchicalData.load('./data', 'TourismSmall')\nY_df['ds'] = pd.to_datetime(Y_df['ds'])\n\n\nY_df.head()\n\n\n\n\n\n\n\n\nunique_id\nds\ny\n\n\n\n\n0\ntotal\n1998-03-31\n84503\n\n\n1\ntotal\n1998-06-30\n65312\n\n\n2\ntotal\n1998-09-30\n72753\n\n\n3\ntotal\n1998-12-31\n70880\n\n\n4\ntotal\n1999-03-31\n86893\n\n\n\n\n\n\n\n\nS_df.iloc[:5, :5]\n\n\n\n\n\n\n\n\nnsw-hol-city\nnsw-hol-noncity\nvic-hol-city\nvic-hol-noncity\nqld-hol-city\n\n\n\n\ntotal\n1.0\n1.0\n1.0\n1.0\n1.0\n\n\nhol\n1.0\n1.0\n1.0\n1.0\n1.0\n\n\nvfr\n0.0\n0.0\n0.0\n0.0\n0.0\n\n\nbus\n0.0\n0.0\n0.0\n0.0\n0.0\n\n\noth\n0.0\n0.0\n0.0\n0.0\n0.0\n\n\n\n\n\n\n\n\ntags\n\n{'Country': array(['total'], dtype=object),\n 'Country/Purpose': array(['hol', 'vfr', 'bus', 'oth'], dtype=object),\n 'Country/Purpose/State': array(['nsw-hol', 'vic-hol', 'qld-hol', 'sa-hol', 'wa-hol', 'tas-hol',\n 'nt-hol', 'nsw-vfr', 'vic-vfr', 'qld-vfr', 'sa-vfr', 'wa-vfr',\n 'tas-vfr', 'nt-vfr', 'nsw-bus', 'vic-bus', 'qld-bus', 'sa-bus',\n 'wa-bus', 'tas-bus', 'nt-bus', 'nsw-oth', 'vic-oth', 'qld-oth',\n 'sa-oth', 'wa-oth', 'tas-oth', 'nt-oth'], dtype=object),\n 'Country/Purpose/State/CityNonCity': array(['nsw-hol-city', 'nsw-hol-noncity', 'vic-hol-city',\n 'vic-hol-noncity', 'qld-hol-city', 'qld-hol-noncity',\n 'sa-hol-city', 'sa-hol-noncity', 'wa-hol-city', 'wa-hol-noncity',\n 'tas-hol-city', 'tas-hol-noncity', 'nt-hol-city', 'nt-hol-noncity',\n 'nsw-vfr-city', 'nsw-vfr-noncity', 'vic-vfr-city',\n 'vic-vfr-noncity', 'qld-vfr-city', 'qld-vfr-noncity',\n 'sa-vfr-city', 'sa-vfr-noncity', 'wa-vfr-city', 'wa-vfr-noncity',\n 'tas-vfr-city', 'tas-vfr-noncity', 'nt-vfr-city', 'nt-vfr-noncity',\n 'nsw-bus-city', 'nsw-bus-noncity', 'vic-bus-city',\n 'vic-bus-noncity', 'qld-bus-city', 'qld-bus-noncity',\n 'sa-bus-city', 'sa-bus-noncity', 'wa-bus-city', 'wa-bus-noncity',\n 'tas-bus-city', 'tas-bus-noncity', 'nt-bus-city', 'nt-bus-noncity',\n 'nsw-oth-city', 'nsw-oth-noncity', 'vic-oth-city',\n 'vic-oth-noncity', 'qld-oth-city', 'qld-oth-noncity',\n 'sa-oth-city', 'sa-oth-noncity', 'wa-oth-city', 'wa-oth-noncity',\n 'tas-oth-city', 'tas-oth-noncity', 'nt-oth-city', 'nt-oth-noncity'],\n dtype=object)}\n\n\nWe split the dataframe in train/test splits.\n\nY_test_df = Y_df.groupby('unique_id').tail(12)\nY_train_df = Y_df.drop(Y_test_df.index)\n\n\nY_test_df = Y_test_df.set_index('unique_id')\nY_train_df = Y_train_df.set_index('unique_id')" + }, + { + "objectID": "examples/tourismsmall.html#base-forecasts", + "href": "examples/tourismsmall.html#base-forecasts", + "title": "Reconciliation Quick Start", + "section": "3. Base forecasts", + "text": "3. Base forecasts\nThe following cell computes the base forecast for each time series using the auto_arima and naive models. Observe that Y_hat_df contains the forecasts but they are not coherent.\n\nfrom statsforecast.core import StatsForecast\nfrom statsforecast.models import AutoARIMA, Naive\n\n\nfcst = StatsForecast(\n df=Y_train_df, \n models=[AutoARIMA(season_length=12), Naive()], \n freq='M', \n n_jobs=-1\n)\nY_hat_df = fcst.forecast(h=12)" + }, + { + "objectID": "examples/tourismsmall.html#hierarchical-reconciliation", + "href": "examples/tourismsmall.html#hierarchical-reconciliation", + "title": "Reconciliation Quick Start", + "section": "4. Hierarchical reconciliation", + "text": "4. Hierarchical reconciliation\nThe following cell makes the previous forecasts coherent using the HierarchicalReconciliation class. The used methods to make the forecasts coherent are:\n\nBottomUp: The reconciliation of the method is a simple addition to the upper levels.\nTopDown: The second method constrains the base-level predictions to the top-most aggregate-level serie and then distributes it to the disaggregate series through the use of proportions.\nMiddleOut: Anchors the base predictions in a middle level.\n\n\nfrom hierarchicalforecast.core import HierarchicalReconciliation\nfrom hierarchicalforecast.methods import BottomUp, TopDown, MiddleOut\n\n\nreconcilers = [\n BottomUp(),\n TopDown(method='forecast_proportions'),\n MiddleOut(middle_level='Country/Purpose/State', \n top_down_method='forecast_proportions')\n]\nhrec = HierarchicalReconciliation(reconcilers=reconcilers)\nY_rec_df = hrec.reconcile(Y_hat_df=Y_hat_df, Y_df=Y_train_df, \n S=S_df, tags=tags)" + }, + { + "objectID": "examples/tourismsmall.html#evaluation", + "href": "examples/tourismsmall.html#evaluation", + "title": "Reconciliation Quick Start", + "section": "5. Evaluation", + "text": "5. Evaluation\nThe HierarchicalForecast package includes the HierarchicalEvaluation class to evaluate the different hierarchies and also is capable of compute scaled metrics compared to a benchmark model.\n\nfrom hierarchicalforecast.evaluation import HierarchicalEvaluation\n\n\ndef mse(y, y_hat):\n return np.mean((y-y_hat)**2)\n\nevaluator = HierarchicalEvaluation(evaluators=[mse])\nevaluation = evaluator.evaluate(\n Y_hat_df=Y_rec_df, Y_test_df=Y_test_df, \n tags=tags, benchmark='Naive'\n)\nevaluation.filter(like='ARIMA', axis=1).T\n\n\n\n\n\n\n\nlevel\nOverall\nCountry\nCountry/Purpose\nCountry/Purpose/State\nCountry/Purpose/State/CityNonCity\n\n\nmetric\nmse-scaled\nmse-scaled\nmse-scaled\nmse-scaled\nmse-scaled\n\n\n\n\nAutoARIMA\n0.958324\n1.051911\n0.903933\n0.909364\n0.845968\n\n\nAutoARIMA/BottomUp\n0.911524\n0.984391\n0.86538\n0.865384\n0.845968\n\n\nAutoARIMA/TopDown_method-forecast_proportions\n0.973036\n1.051911\n0.88765\n0.973843\n0.949449\n\n\nAutoARIMA/MiddleOut_middle_level-Country/Purpose/State_top_down_method-forecast_proportions\n0.896147\n0.950773\n0.830191\n0.909364\n0.885306\n\n\n\n\n\n\n\n\nReferences\n\nOrcutt, G.H., Watts, H.W., & Edwards, J.B.(1968). Data aggregation and information loss. The American Economic Review, 58 , 773{787).\nDisaggregation methods to expedite product line forecasting. Journal of Forecasting, 9 , 233ā254. doi:10.1002/for.3980090304.\nAn investigation of aggregate variable time series forecast strategies with specific subaggregate time series statistical correlation. Computers and Operations Research, 26 , 1133ā1149. doi:10.1016/S0305-0548(99)00017-9.\nHyndman, R.J., & Athanasopoulos, G. (2021). āForecasting: principles and practice, 3rd edition: Chapter 11: Forecasting hierarchical and grouped series.ā. OTexts: Melbourne, Australia. OTexts.com/fpp3 Accessed on July 2022." + }, + { + "objectID": "examples/australianprisonpopulation.html", + "href": "examples/australianprisonpopulation.html", + "title": "Geographical Aggregation (Prison Population)", + "section": "", + "text": "In many applications, a set of time series is hierarchically organized. Examples include the presence of geographic levels, products, or categories that define different types of aggregations. In such scenarios, forecasters are often required to provide predictions for all disaggregate and aggregate series. A natural desire is for those predictions to be ācoherentā, that is, for the bottom series to add up precisely to the forecasts of the aggregated series.\nIn this notebook we present an example on how to use HierarchicalForecast to produce coherent forecasts between geographical levels. We will use the Australian Prison Population dataset.\nWe will first load the dataset and produce base forecasts using an ETS model from StatsForecast, and then reconciliate the forecasts with several reconciliation algorithms from HierarchicalForecast. Finally, we show the performance is comparable with the results reported by the Forecasting: Principles and Practice which uses the R package fable.\nYou can run these experiments using CPU or GPU with Google Colab.\n!pip install hierarchicalforecast\n!pip install -U statsforecast numba\nIf you find the code useful, please ā us on Github" + }, + { + "objectID": "examples/australianprisonpopulation.html#load-and-process-data", + "href": "examples/australianprisonpopulation.html#load-and-process-data", + "title": "Geographical Aggregation (Prison Population)", + "section": "1. Load and Process Data", + "text": "1. Load and Process Data\nThe dataset only contains the time series at the lowest level, so we need to create the time series for all hierarchies.\n\nimport numpy as np\nimport pandas as pd\n\n\nY_df = pd.read_csv('https://OTexts.com/fpp3/extrafiles/prison_population.csv')\nY_df = Y_df.rename({'Count': 'y', 'Date': 'ds'}, axis=1)\nY_df.insert(0, 'Country', 'Australia')\nY_df = Y_df[['Country', 'State', 'Gender', 'Legal', 'Indigenous', 'ds', 'y']]\nY_df['ds'] = pd.to_datetime(Y_df['ds'])\nY_df.head()\n\n\n\n\n\n\n\n\nCountry\nState\nGender\nLegal\nIndigenous\nds\ny\n\n\n\n\n0\nAustralia\nACT\nFemale\nRemanded\nATSI\n2005-03-01\n0\n\n\n1\nAustralia\nACT\nFemale\nRemanded\nNon-ATSI\n2005-03-01\n2\n\n\n2\nAustralia\nACT\nFemale\nSentenced\nATSI\n2005-03-01\n0\n\n\n3\nAustralia\nACT\nFemale\nSentenced\nNon-ATSI\n2005-03-01\n5\n\n\n4\nAustralia\nACT\nMale\nRemanded\nATSI\n2005-03-01\n7\n\n\n\n\n\n\n\nThe dataset can be grouped in the following grouped structure.\n\nhiers = [\n ['Country'],\n ['Country', 'State'], \n ['Country', 'Gender'], \n ['Country', 'Legal'], \n ['Country', 'State', 'Gender', 'Legal']\n]\n\nUsing the aggregate function from HierarchicalForecast we can get the full set of time series.\n\nfrom hierarchicalforecast.utils import aggregate\n\n\nY_df, S_df, tags = aggregate(Y_df, hiers)\nY_df['y'] = Y_df['y']/1e3\nY_df = Y_df.reset_index()\n\n\nY_df.head()\n\n\n\n\n\n\n\n\nunique_id\nds\ny\n\n\n\n\n0\nAustralia\n2005-03-01\n24.296\n\n\n1\nAustralia\n2005-06-01\n24.643\n\n\n2\nAustralia\n2005-09-01\n24.511\n\n\n3\nAustralia\n2005-12-01\n24.393\n\n\n4\nAustralia\n2006-03-01\n24.524\n\n\n\n\n\n\n\n\nS_df.iloc[:5, :5]\n\n\n\n\n\n\n\n\nAustralia/ACT/Female/Remanded\nAustralia/ACT/Female/Sentenced\nAustralia/ACT/Male/Remanded\nAustralia/ACT/Male/Sentenced\nAustralia/NSW/Female/Remanded\n\n\n\n\nAustralia\n1.0\n1.0\n1.0\n1.0\n1.0\n\n\nAustralia/ACT\n1.0\n1.0\n1.0\n1.0\n0.0\n\n\nAustralia/NSW\n0.0\n0.0\n0.0\n0.0\n1.0\n\n\nAustralia/NT\n0.0\n0.0\n0.0\n0.0\n0.0\n\n\nAustralia/QLD\n0.0\n0.0\n0.0\n0.0\n0.0\n\n\n\n\n\n\n\n\ntags\n\n{'Country': array(['Australia'], dtype=object),\n 'Country/State': array(['Australia/ACT', 'Australia/NSW', 'Australia/NT', 'Australia/QLD',\n 'Australia/SA', 'Australia/TAS', 'Australia/VIC', 'Australia/WA'],\n dtype=object),\n 'Country/Gender': array(['Australia/Female', 'Australia/Male'], dtype=object),\n 'Country/Legal': array(['Australia/Remanded', 'Australia/Sentenced'], dtype=object),\n 'Country/State/Gender/Legal': ['Australia/ACT/Female/Remanded',\n 'Australia/ACT/Female/Sentenced',\n 'Australia/ACT/Male/Remanded',\n 'Australia/ACT/Male/Sentenced',\n 'Australia/NSW/Female/Remanded',\n 'Australia/NSW/Female/Sentenced',\n 'Australia/NSW/Male/Remanded',\n 'Australia/NSW/Male/Sentenced',\n 'Australia/NT/Female/Remanded',\n 'Australia/NT/Female/Sentenced',\n 'Australia/NT/Male/Remanded',\n 'Australia/NT/Male/Sentenced',\n 'Australia/QLD/Female/Remanded',\n 'Australia/QLD/Female/Sentenced',\n 'Australia/QLD/Male/Remanded',\n 'Australia/QLD/Male/Sentenced',\n 'Australia/SA/Female/Remanded',\n 'Australia/SA/Female/Sentenced',\n 'Australia/SA/Male/Remanded',\n 'Australia/SA/Male/Sentenced',\n 'Australia/TAS/Female/Remanded',\n 'Australia/TAS/Female/Sentenced',\n 'Australia/TAS/Male/Remanded',\n 'Australia/TAS/Male/Sentenced',\n 'Australia/VIC/Female/Remanded',\n 'Australia/VIC/Female/Sentenced',\n 'Australia/VIC/Male/Remanded',\n 'Australia/VIC/Male/Sentenced',\n 'Australia/WA/Female/Remanded',\n 'Australia/WA/Female/Sentenced',\n 'Australia/WA/Male/Remanded',\n 'Australia/WA/Male/Sentenced']}\n\n\n\nSplit Train/Test sets\nWe use the final two years (8 quarters) as test set.\n\nY_test_df = Y_df.groupby('unique_id').tail(8)\nY_train_df = Y_df.drop(Y_test_df.index)\n\n\nY_test_df = Y_test_df.set_index('unique_id')\nY_train_df = Y_train_df.set_index('unique_id')" + }, + { + "objectID": "examples/australianprisonpopulation.html#computing-base-forecasts", + "href": "examples/australianprisonpopulation.html#computing-base-forecasts", + "title": "Geographical Aggregation (Prison Population)", + "section": "2. Computing base forecasts", + "text": "2. Computing base forecasts\nThe following cell computes the base forecasts for each time series in Y_df using the ETS model. Observe that Y_hat_df contains the forecasts but they are not coherent.\n\nfrom statsforecast.models import ETS\nfrom statsforecast.core import StatsForecast\n\n\nfcst = StatsForecast(df=Y_train_df,\n models=[ETS(season_length=4, model='ZMZ')], \n freq='QS', n_jobs=-1)\nY_hat_df = fcst.forecast(h=8, fitted=True)\nY_fitted_df = fcst.forecast_fitted_values()" + }, + { + "objectID": "examples/australianprisonpopulation.html#reconcile-forecasts", + "href": "examples/australianprisonpopulation.html#reconcile-forecasts", + "title": "Geographical Aggregation (Prison Population)", + "section": "3. Reconcile forecasts", + "text": "3. Reconcile forecasts\nThe following cell makes the previous forecasts coherent using the HierarchicalReconciliation class. Since the hierarchy structure is not strict, we canāt use methods such as TopDown or MiddleOut. In this example we use BottomUp and MinTrace.\n\nfrom hierarchicalforecast.methods import BottomUp, MinTrace\nfrom hierarchicalforecast.core import HierarchicalReconciliation\n\n\nreconcilers = [\n BottomUp(),\n MinTrace(method='mint_shrink')\n]\nhrec = HierarchicalReconciliation(reconcilers=reconcilers)\nY_rec_df = hrec.reconcile(Y_hat_df=Y_hat_df, Y_df=Y_fitted_df, S=S_df, tags=tags)\n\nThe dataframe Y_rec_df contains the reconciled forecasts.\n\nY_rec_df.head()\n\n\n\n\n\n\n\n\nds\nETS\nETS/BottomUp\nETS/MinTrace_method-mint_shrink\n\n\nunique_id\n\n\n\n\n\n\n\n\nAustralia\n2015-01-01\n34.799496\n34.933891\n34.927244\n\n\nAustralia\n2015-04-01\n35.192638\n35.473560\n35.440861\n\n\nAustralia\n2015-07-01\n35.188217\n35.687363\n35.476427\n\n\nAustralia\n2015-10-01\n35.888626\n36.010685\n35.946153\n\n\nAustralia\n2016-01-01\n36.045437\n36.400101\n36.244707" + }, + { + "objectID": "examples/australianprisonpopulation.html#evaluation", + "href": "examples/australianprisonpopulation.html#evaluation", + "title": "Geographical Aggregation (Prison Population)", + "section": "4. Evaluation", + "text": "4. Evaluation\nThe HierarchicalForecast package includes the HierarchicalEvaluation class to evaluate the different hierarchies and also is capable of compute scaled metrics compared to a benchmark model.\n\nfrom hierarchicalforecast.evaluation import HierarchicalEvaluation\n\n\ndef mase(y, y_hat, y_insample, seasonality=4):\n errors = np.mean(np.abs(y - y_hat), axis=1)\n scale = np.mean(np.abs(y_insample[:, seasonality:] - y_insample[:, :-seasonality]), axis=1)\n return np.mean(errors / scale)\n\neval_tags = {}\neval_tags['Total'] = tags['Country']\neval_tags['State'] = tags['Country/State']\neval_tags['Legal status'] = tags['Country/Legal']\neval_tags['Gender'] = tags['Country/Gender']\neval_tags['Bottom'] = tags['Country/State/Gender/Legal']\neval_tags['All series'] = np.concatenate(list(tags.values()))\n\nevaluator = HierarchicalEvaluation(evaluators=[mase])\nevaluation = evaluator.evaluate(\n Y_hat_df=Y_rec_df, Y_test_df=Y_test_df,\n tags=eval_tags,\n Y_df=Y_train_df\n)\nevaluation = evaluation.reset_index().drop(columns='metric').drop(0).set_index('level')\nevaluation.columns = ['Base', 'BottomUp', 'MinTrace(mint_shrink)']\nevaluation.applymap('{:.2f}'.format)\n\n\n\n\n\n\n\n\nBase\nBottomUp\nMinTrace(mint_shrink)\n\n\nlevel\n\n\n\n\n\n\n\nTotal\n1.36\n1.02\n1.16\n\n\nState\n1.54\n1.57\n1.61\n\n\nLegal status\n2.40\n2.50\n2.40\n\n\nGender\n1.08\n0.81\n0.95\n\n\nBottom\n2.17\n2.17\n2.16\n\n\nAll series\n2.00\n2.00\n2.00\n\n\n\n\n\n\n\n\nFable Comparison\nObserve that we can recover the results reported by the Forecasting: Principles and Practice book. The original results were calculated using the R package fable.\n\n\n\nFableās reconciliation results\n\n\n\n\nReferences\n\nHyndman, R.J., & Athanasopoulos, G. (2021). āForecasting: principles and practice, 3rd edition: Chapter 11: Forecasting hierarchical and grouped series.ā. OTexts: Melbourne, Australia. OTexts.com/fpp3 Accessed on July 2022.\nRob Hyndman, Alan Lee, Earo Wang, Shanika Wickramasuriya, and Maintainer Earo Wang (2021). āhts: Hierarchical and Grouped Time Seriesā. URL https://CRAN.R-project.org/package=hts. R package version 0.3.1.\nMitchell OāHara-Wild, Rob Hyndman, Earo Wang, Gabriel Caceres, Tim-Gunnar Hensel, and Timothy Hyndman (2021). āfable: Forecasting Models for Tidy Time Seriesā. URL https://CRAN.R-project.org/package=fable. R package version 6.0.2." + }, + { + "objectID": "index.html", + "href": "index.html", + "title": "Hierarchical Forecast š", + "section": "", + "text": "Large collections of time series organized into structures at different aggregation levels often require their forecasts to follow their aggregation constraints, which poses the challenge of creating novel algorithms capable of coherent forecasts.\nHierarchicalForecast offers a collection of reconciliation methods, including BottomUp, TopDown, MiddleOut, MinTrace and ERM. And Probabilistic coherent predictions including Normality, Bootstrap, and PERMBU.\nIf you find the code useful, please ā us on Github" + }, + { + "objectID": "index.html#features", + "href": "index.html#features", + "title": "Hierarchical Forecast š", + "section": "š Features", + "text": "š Features\n\nClassic reconciliation methods:\n\nBottomUp: Simple addition to the upper levels.\nTopDown: Distributes the top levels forecasts trough the hierarchies.\n\nAlternative reconciliation methods:\n\nMiddleOut: It anchors the base predictions in a middle level. The levels above the base predictions use the bottom-up approach, while the levels below use a top-down.\nMinTrace: Minimizes the total forecast variance of the space of coherent forecasts, with the Minimum Trace reconciliation.\nERM: Optimizes the reconciliation matrix minimizing an L1 regularized objective.\n\nProbabilistic coherent methods:\n\nNormality: Uses MinTrace variance-covariance closed form matrix under a normality assumption.\nBootstrap: Generates distribution of hierarchically reconciled predictions using Gamakumaraās bootstrap approach.\nPERMBU: Reconciles independent sample predictions by reinjecting multivariate dependence with estimated rank permutation copulas, and performing a Bottom-Up aggregation.\n\n\nMissing something? Please open an issue here or write us in" + }, + { + "objectID": "index.html#why", + "href": "index.html#why", + "title": "Hierarchical Forecast š", + "section": "š Why?", + "text": "š Why?\nShort: We want to contribute to the ML field by providing reliable baselines and benchmarks for hierarchical forecasting task in industry and academia. Hereās the complete paper.\nVerbose: HierarchicalForecast integrates publicly available processed datasets, evaluation metrics, and a curated set of statistical baselines. In this library we provide usage examples and references to extensive experiments where we showcase the baselineās use and evaluate the accuracy of their predictions. With this work, we hope to contribute to Machine Learning forecasting by bridging the gap to statistical and econometric modeling, as well as providing tools for the development of novel hierarchical forecasting algorithms rooted in a thorough comparison of these well-established models. We intend to continue maintaining and increasing the repository, promoting collaboration across the forecasting community." + }, + { + "objectID": "index.html#installation", + "href": "index.html#installation", + "title": "Hierarchical Forecast š", + "section": "š» Installation", + "text": "š» Installation\n\nPyPI\nYou can install the released version of HierarchicalForecast from the Python package index with:\npip install hierarchicalforecast\n(Installing inside a python virtualenvironment or a conda environment is recommended.)\n\n\nConda\nAlso you can install the released version of HierarchicalForecast from conda with:\nconda install -c conda-forge hierarchicalforecast\n(Installing inside a python virtualenvironment or a conda environment is recommended.)\n\n\nDev Mode\nIf you want to make some modifications to the code and see the effects in real time (without reinstalling), follow the steps below:\ngit clone https://github.com/Nixtla/hierarchicalforecast.git\ncd hierarchicalforecast\npip install -e ." + }, + { + "objectID": "index.html#how-to-use", + "href": "index.html#how-to-use", + "title": "Hierarchical Forecast š", + "section": "š§¬ How to use", + "text": "š§¬ How to use\nThe following example needs statsforecast and datasetsforecast as additional packages. If not installed, install it via your preferred method, e.g. pip install statsforecast datasetsforecast. The datasetsforecast library allows us to download hierarhical datasets and we will use statsforecast to compute base forecasts to be reconciled.\nYou can open this example in Colab \nimport numpy as np\nimport pandas as pd\n\n#obtain hierarchical dataset\nfrom datasetsforecast.hierarchical import HierarchicalData\n\n# compute base forecast no coherent\nfrom statsforecast.core import StatsForecast\nfrom statsforecast.models import AutoARIMA, Naive\n\n#obtain hierarchical reconciliation methods and evaluation\nfrom hierarchicalforecast.core import HierarchicalReconciliation\nfrom hierarchicalforecast.evaluation import HierarchicalEvaluation\nfrom hierarchicalforecast.methods import BottomUp, TopDown, MiddleOut\n\n\n# Load TourismSmall dataset\nY_df, S, tags = HierarchicalData.load('./data', 'TourismSmall')\nY_df['ds'] = pd.to_datetime(Y_df['ds'])\n\n#split train/test sets\nY_test_df = Y_df.groupby('unique_id').tail(12)\nY_train_df = Y_df.drop(Y_test_df.index)\nY_test_df = Y_test_df.set_index('unique_id')\nY_train_df = Y_train_df.set_index('unique_id')\n\n# Compute base auto-ARIMA predictions\nfcst = StatsForecast(df=Y_train_df, \n models=[AutoARIMA(season_length=12), Naive()], \n freq='M', n_jobs=-1)\nY_hat_df = fcst.forecast(h=12)\n\n# Reconcile the base predictions\nreconcilers = [\n BottomUp(),\n TopDown(method='forecast_proportions'),\n MiddleOut(middle_level='Country/Purpose/State',\n top_down_method='forecast_proportions')\n]\nhrec = HierarchicalReconciliation(reconcilers=reconcilers)\nY_rec_df = hrec.reconcile(Y_hat_df=Y_hat_df, Y_df=Y_train_df, \n S=S, tags=tags)\n\nEvaluation\ndef mse(y, y_hat):\n return np.mean((y-y_hat)**2)\n\nevaluator = HierarchicalEvaluation(evaluators=[mse])\nevaluator.evaluate(Y_h=Y_rec_df, Y_test=Y_df_test, \n tags=tags, benchmark='Naive')" + }, + { + "objectID": "index.html#how-to-cite", + "href": "index.html#how-to-cite", + "title": "Hierarchical Forecast š", + "section": "How to cite", + "text": "How to cite\nHereās the complete paper.\n@article{olivares2022hierarchicalforecast,\n author = {Kin G. Olivares and\n Federico Garza and \n David Luo and \n Cristian ChallĆŗ and\n Max Mergenthaler and\n Souhaib Ben Taieb and\n Shanika L. Wickramasuriya and\n Artur Dubrawski},\n title = {{HierarchicalForecast}: A Reference Framework for Hierarchical Forecasting in Python},\n journal = {Work in progress paper, submitted to Journal of Machine Learning Research.},\n volume = {abs/2207.03517},\n year = {2022},\n url = {https://arxiv.org/abs/2207.03517},\n archivePrefix = {arXiv}\n}" + }, + { + "objectID": "core.html", + "href": "core.html", + "title": " Core ", + "section": "", + "text": "HierarchicalForecast contains pure Python implementations of hierarchical reconciliation methods as well as a core.HierarchicalReconciliation wrapper class that enables easy interaction with these methods through pandas DataFrames containing the hierarchical time series and the base predictions.\nThe core.HierarchicalReconciliation reconciliation class operates with the hierarchical time series pd.DataFrame Y_df, the base predictions pd.DataFrame Y_hat_df, the aggregation constraints matrix S. For more information on the creation of aggregation constraints matrix see the utils aggregation method.\n\n core.HierarchicalReconciliation \n\nsource\n\ninit\n\n init (reconcilers:List[Callable])\n\nHierarchical Reconciliation Class.\nThe core.HierarchicalReconciliation class allows you to efficiently fit multiple HierarchicaForecast methods for a collection of time series and base predictions stored in pandas DataFrames. The Y_df dataframe identifies series and datestamps with the unique_id and ds columns while the y column denotes the target time series variable. The Y_h dataframe stores the base predictions, example (AutoARIMA, ETS, etc.).\nParameters: reconcilers: A list of instantiated classes of the reconciliation methods module .\nReferences: Rob J. Hyndman and George Athanasopoulos (2018). āForecasting principles and practice, Hierarchical and Grouped Seriesā.\n\nsource\n\n\nHierarchicalReconciliation\n\n HierarchicalReconciliation (reconcilers:List[Callable])\n\nHierarchical Reconciliation Class.\nThe core.HierarchicalReconciliation class allows you to efficiently fit multiple HierarchicaForecast methods for a collection of time series and base predictions stored in pandas DataFrames. The Y_df dataframe identifies series and datestamps with the unique_id and ds columns while the y column denotes the target time series variable. The Y_h dataframe stores the base predictions, example (AutoARIMA, ETS, etc.).\nParameters: reconcilers: A list of instantiated classes of the reconciliation methods module .\nReferences: Rob J. Hyndman and George Athanasopoulos (2018). āForecasting principles and practice, Hierarchical and Grouped Seriesā.\n\nsource\n\n\nreconcile\n\n reconcile (Y_hat_df:pandas.core.frame.DataFrame,\n S:pandas.core.frame.DataFrame, tags:Dict[str,numpy.ndarray],\n Y_df:Optional[pandas.core.frame.DataFrame]=None,\n level:Optional[List[int]]=None,\n intervals_method:str='normality', num_samples:int=-1,\n seed:int=0, sort_df:bool=True, is_balanced:bool=False)\n\nHierarchical Reconciliation Method.\nThe reconcile method is analogous to SKLearn fit_predict method, it applies different reconciliation techniques instantiated in the reconcilers list.\nMost reconciliation methods can be described by the following convenient linear algebra notation:\n\\[\\tilde{\\mathbf{y}}_{[a,b],\\tau} = \\mathbf{S}_{[a,b][b]} \\mathbf{P}_{[b][a,b]} \\hat{\\mathbf{y}}_{[a,b],\\tau}\\]\nwhere \\(a, b\\) represent the aggregate and bottom levels, \\(\\mathbf{S}_{[a,b][b]}\\) contains the hierarchical aggregation constraints, and \\(\\mathbf{P}_{[b][a,b]}\\) varies across reconciliation methods. The reconciled predictions are \\(\\tilde{\\mathbf{y}}_{[a,b],\\tau}\\), and the base predictions \\(\\hat{\\mathbf{y}}_{[a,b],\\tau}\\).\nParameters: Y_hat_df: pd.DataFrame, base forecasts with columns ds and models to reconcile indexed by unique_id. Y_df: pd.DataFrame, training set of base time series with columns ['ds', 'y'] indexed by unique_id. If a class of self.reconciles receives y_hat_insample, Y_df must include them as columns. S: pd.DataFrame with summing matrix of size (base, bottom), see aggregate method. tags: Each key is a level and its value contains tags associated to that level. level: positive float list [0,100), confidence levels for prediction intervals. intervals_method: str, method used to calculate prediction intervals, one of normality, bootstrap, permbu. num_samples: int=-1, if positive return that many probabilistic coherent samples. seed: int=0, random seed for numpy generatorās replicability. sort_df : bool (default=True), if True, sort df by [unique_id,ds]. is_balanced: bool=False, wether Y_df is balanced, set it to True to speed things up if Y_df is balanced.\nReturns: Y_tilde_df: pd.DataFrame, with reconciled predictions.\n\nsource\n\n\nbootstrap_reconcile\n\n bootstrap_reconcile (Y_hat_df:pandas.core.frame.DataFrame,\n S_df:pandas.core.frame.DataFrame,\n tags:Dict[str,numpy.ndarray],\n Y_df:Optional[pandas.core.frame.DataFrame]=None,\n level:Optional[List[int]]=None,\n intervals_method:str='normality',\n num_samples:int=-1, num_seeds:int=1,\n sort_df:bool=True)\n\nBootstraped Hierarchical Reconciliation Method.\nApplies N times, based on different random seeds, the reconcile method for the different reconciliation techniques instantiated in the reconcilers list.\nParameters: Y_hat_df: pd.DataFrame, base forecasts with columns ds and models to reconcile indexed by unique_id. Y_df: pd.DataFrame, training set of base time series with columns ['ds', 'y'] indexed by unique_id. If a class of self.reconciles receives y_hat_insample, Y_df must include them as columns. S: pd.DataFrame with summing matrix of size (base, bottom), see aggregate method. tags: Each key is a level and its value contains tags associated to that level. level: positive float list [0,100), confidence levels for prediction intervals. intervals_method: str, method used to calculate prediction intervals, one of normality, bootstrap, permbu. num_samples: int=-1, if positive return that many probabilistic coherent samples. num_seeds: int=1, random seed for numpy generatorās replicability. sort_df : bool (default=True), if True, sort df by [unique_id,ds].\nReturns: Y_bootstrap_df: pd.DataFrame, with bootstraped reconciled predictions.\n\n\n\n Example \n\nimport numpy as np\nimport pandas as pd\n\nfrom statsforecast.core import StatsForecast\nfrom statsforecast.models import ETS, Naive\n\nfrom hierarchicalforecast.utils import aggregate\nfrom hierarchicalforecast.core import HierarchicalReconciliation\nfrom hierarchicalforecast.methods import BottomUp, MinTrace\n\n# Load TourismSmall dataset\ndf = pd.read_csv('https://raw.githubusercontent.com/Nixtla/transfer-learning-time-series/main/datasets/tourism.csv')\ndf = df.rename({'Trips': 'y', 'Quarter': 'ds'}, axis=1)\ndf.insert(0, 'Country', 'Australia')\n\n# Create hierarchical seires based on geographic levels and purpose\n# And Convert quarterly ds string to pd.datetime format\nhierarchy_levels = [['Country'],\n ['Country', 'State'], \n ['Country', 'Purpose'], \n ['Country', 'State', 'Region'], \n ['Country', 'State', 'Purpose'], \n ['Country', 'State', 'Region', 'Purpose']]\n\nY_df, S_df, tags = aggregate(df=df, spec=hierarchy_levels)\nqs = Y_df['ds'].str.replace(r'(\\d+) (Q\\d)', r'\\1-\\2', regex=True)\nY_df['ds'] = pd.PeriodIndex(qs, freq='Q').to_timestamp()\nY_df = Y_df.reset_index()\n\n# Split train/test sets\nY_test_df = Y_df.groupby('unique_id').tail(4)\nY_train_df = Y_df.drop(Y_test_df.index)\n\n# Compute base auto-ETS predictions\n# Careful identifying correct data freq, this data quarterly 'Q'\nfcst = StatsForecast(df=Y_train_df,\n #models=[ETS(season_length=12), Naive()],\n models=[Naive()],\n freq='Q', n_jobs=-1)\nY_hat_df = fcst.forecast(h=4, fitted=True)\nY_fitted_df = fcst.forecast_fitted_values()\n\n# Reconcile the base predictions\nY_train_df = Y_train_df.reset_index().set_index('unique_id')\nY_hat_df = Y_hat_df.reset_index().set_index('unique_id')\nreconcilers = [BottomUp(),\n MinTrace(method='mint_shrink')]\nhrec = HierarchicalReconciliation(reconcilers=reconcilers)\nY_rec_df = hrec.reconcile(Y_hat_df=Y_hat_df, \n Y_df=Y_fitted_df,\n S=S_df, tags=tags)\nY_rec_df.groupby('unique_id').head(2)\n\n\n\n\n\nIf you find the code useful, please ā us on Github" + } +] \ No newline at end of file diff --git a/site_libs/bootstrap/bootstrap-icons.css b/site_libs/bootstrap/bootstrap-icons.css new file mode 100644 index 00000000..94f19404 --- /dev/null +++ b/site_libs/bootstrap/bootstrap-icons.css @@ -0,0 +1,2018 @@ +@font-face { + font-display: block; + font-family: "bootstrap-icons"; + src: +url("./bootstrap-icons.woff?2ab2cbbe07fcebb53bdaa7313bb290f2") format("woff"); +} + +.bi::before, +[class^="bi-"]::before, +[class*=" bi-"]::before { + display: inline-block; + font-family: bootstrap-icons !important; + font-style: normal; + font-weight: normal !important; + font-variant: normal; + text-transform: none; + line-height: 1; + vertical-align: -.125em; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +.bi-123::before { content: "\f67f"; } +.bi-alarm-fill::before { content: "\f101"; } +.bi-alarm::before { content: "\f102"; } +.bi-align-bottom::before { content: "\f103"; } +.bi-align-center::before { content: "\f104"; } +.bi-align-end::before { content: "\f105"; } +.bi-align-middle::before { content: "\f106"; } +.bi-align-start::before { content: "\f107"; } +.bi-align-top::before { content: "\f108"; } +.bi-alt::before { content: "\f109"; } +.bi-app-indicator::before { content: "\f10a"; } +.bi-app::before { content: "\f10b"; } +.bi-archive-fill::before { content: "\f10c"; } +.bi-archive::before { content: "\f10d"; } +.bi-arrow-90deg-down::before { content: "\f10e"; } +.bi-arrow-90deg-left::before { content: "\f10f"; } +.bi-arrow-90deg-right::before { content: "\f110"; } +.bi-arrow-90deg-up::before { content: "\f111"; } +.bi-arrow-bar-down::before { content: "\f112"; } +.bi-arrow-bar-left::before { content: "\f113"; } +.bi-arrow-bar-right::before { content: "\f114"; } +.bi-arrow-bar-up::before { content: "\f115"; } +.bi-arrow-clockwise::before { content: "\f116"; } +.bi-arrow-counterclockwise::before { content: "\f117"; } +.bi-arrow-down-circle-fill::before { content: "\f118"; } +.bi-arrow-down-circle::before { content: "\f119"; } +.bi-arrow-down-left-circle-fill::before { content: "\f11a"; } +.bi-arrow-down-left-circle::before { content: "\f11b"; } +.bi-arrow-down-left-square-fill::before { content: "\f11c"; } +.bi-arrow-down-left-square::before { content: "\f11d"; } +.bi-arrow-down-left::before { content: "\f11e"; } +.bi-arrow-down-right-circle-fill::before { content: "\f11f"; } +.bi-arrow-down-right-circle::before { content: "\f120"; } +.bi-arrow-down-right-square-fill::before { content: "\f121"; } +.bi-arrow-down-right-square::before { content: "\f122"; } +.bi-arrow-down-right::before { content: "\f123"; } +.bi-arrow-down-short::before { content: "\f124"; } +.bi-arrow-down-square-fill::before { content: "\f125"; } +.bi-arrow-down-square::before { content: "\f126"; } +.bi-arrow-down-up::before { content: "\f127"; } +.bi-arrow-down::before { content: "\f128"; } +.bi-arrow-left-circle-fill::before { content: "\f129"; } +.bi-arrow-left-circle::before { content: "\f12a"; } +.bi-arrow-left-right::before { content: "\f12b"; } +.bi-arrow-left-short::before { content: "\f12c"; } +.bi-arrow-left-square-fill::before { content: "\f12d"; } +.bi-arrow-left-square::before { content: "\f12e"; } +.bi-arrow-left::before { content: "\f12f"; } +.bi-arrow-repeat::before { content: "\f130"; } +.bi-arrow-return-left::before { content: "\f131"; } +.bi-arrow-return-right::before { content: "\f132"; } +.bi-arrow-right-circle-fill::before { content: "\f133"; } +.bi-arrow-right-circle::before { content: "\f134"; } +.bi-arrow-right-short::before { content: "\f135"; } +.bi-arrow-right-square-fill::before { content: "\f136"; } +.bi-arrow-right-square::before { content: "\f137"; } +.bi-arrow-right::before { content: "\f138"; } +.bi-arrow-up-circle-fill::before { content: "\f139"; } +.bi-arrow-up-circle::before { content: "\f13a"; } +.bi-arrow-up-left-circle-fill::before { content: "\f13b"; } +.bi-arrow-up-left-circle::before { content: "\f13c"; } +.bi-arrow-up-left-square-fill::before { content: "\f13d"; } +.bi-arrow-up-left-square::before { content: "\f13e"; } +.bi-arrow-up-left::before { content: "\f13f"; } +.bi-arrow-up-right-circle-fill::before { content: "\f140"; } +.bi-arrow-up-right-circle::before { content: "\f141"; } +.bi-arrow-up-right-square-fill::before { content: "\f142"; } +.bi-arrow-up-right-square::before { content: "\f143"; } +.bi-arrow-up-right::before { content: "\f144"; } +.bi-arrow-up-short::before { content: "\f145"; } +.bi-arrow-up-square-fill::before { content: "\f146"; } +.bi-arrow-up-square::before { content: "\f147"; } +.bi-arrow-up::before { content: "\f148"; } +.bi-arrows-angle-contract::before { content: "\f149"; } +.bi-arrows-angle-expand::before { content: "\f14a"; } +.bi-arrows-collapse::before { content: "\f14b"; } +.bi-arrows-expand::before { content: "\f14c"; } +.bi-arrows-fullscreen::before { content: "\f14d"; } +.bi-arrows-move::before { content: "\f14e"; } +.bi-aspect-ratio-fill::before { content: "\f14f"; } +.bi-aspect-ratio::before { content: "\f150"; } +.bi-asterisk::before { content: "\f151"; } +.bi-at::before { content: "\f152"; } +.bi-award-fill::before { content: "\f153"; } +.bi-award::before { content: "\f154"; } +.bi-back::before { content: "\f155"; } +.bi-backspace-fill::before { content: "\f156"; } +.bi-backspace-reverse-fill::before { content: "\f157"; } +.bi-backspace-reverse::before { content: "\f158"; } +.bi-backspace::before { content: "\f159"; } +.bi-badge-3d-fill::before { content: "\f15a"; } +.bi-badge-3d::before { content: "\f15b"; } +.bi-badge-4k-fill::before { content: "\f15c"; } +.bi-badge-4k::before { content: "\f15d"; } +.bi-badge-8k-fill::before { content: "\f15e"; } +.bi-badge-8k::before { content: "\f15f"; } +.bi-badge-ad-fill::before { content: "\f160"; } +.bi-badge-ad::before { content: "\f161"; } +.bi-badge-ar-fill::before { content: "\f162"; } +.bi-badge-ar::before { content: "\f163"; } +.bi-badge-cc-fill::before { content: "\f164"; } +.bi-badge-cc::before { content: "\f165"; } +.bi-badge-hd-fill::before { content: "\f166"; } +.bi-badge-hd::before { content: "\f167"; } +.bi-badge-tm-fill::before { content: "\f168"; } +.bi-badge-tm::before { content: "\f169"; } +.bi-badge-vo-fill::before { content: "\f16a"; } +.bi-badge-vo::before { content: "\f16b"; } +.bi-badge-vr-fill::before { content: "\f16c"; } +.bi-badge-vr::before { content: "\f16d"; } +.bi-badge-wc-fill::before { content: "\f16e"; } +.bi-badge-wc::before { content: "\f16f"; } +.bi-bag-check-fill::before { content: "\f170"; } +.bi-bag-check::before { content: "\f171"; } +.bi-bag-dash-fill::before { content: "\f172"; } +.bi-bag-dash::before { content: "\f173"; } +.bi-bag-fill::before { content: "\f174"; } +.bi-bag-plus-fill::before { content: "\f175"; } +.bi-bag-plus::before { content: "\f176"; } +.bi-bag-x-fill::before { content: "\f177"; } +.bi-bag-x::before { content: "\f178"; } +.bi-bag::before { content: "\f179"; } +.bi-bar-chart-fill::before { content: "\f17a"; } +.bi-bar-chart-line-fill::before { content: "\f17b"; } +.bi-bar-chart-line::before { content: "\f17c"; } +.bi-bar-chart-steps::before { content: "\f17d"; } +.bi-bar-chart::before { content: "\f17e"; } +.bi-basket-fill::before { content: "\f17f"; } +.bi-basket::before { content: "\f180"; } +.bi-basket2-fill::before { content: "\f181"; } +.bi-basket2::before { content: "\f182"; } +.bi-basket3-fill::before { content: "\f183"; } +.bi-basket3::before { content: "\f184"; } +.bi-battery-charging::before { content: "\f185"; } +.bi-battery-full::before { content: "\f186"; } +.bi-battery-half::before { content: "\f187"; } +.bi-battery::before { content: "\f188"; } +.bi-bell-fill::before { content: "\f189"; } +.bi-bell::before { content: "\f18a"; } +.bi-bezier::before { content: "\f18b"; } +.bi-bezier2::before { content: "\f18c"; } +.bi-bicycle::before { content: "\f18d"; } +.bi-binoculars-fill::before { content: "\f18e"; } +.bi-binoculars::before { content: "\f18f"; } +.bi-blockquote-left::before { content: "\f190"; } +.bi-blockquote-right::before { content: "\f191"; } +.bi-book-fill::before { content: "\f192"; } +.bi-book-half::before { content: "\f193"; } +.bi-book::before { content: "\f194"; } +.bi-bookmark-check-fill::before { content: "\f195"; } +.bi-bookmark-check::before { content: "\f196"; } +.bi-bookmark-dash-fill::before { content: "\f197"; } +.bi-bookmark-dash::before { content: "\f198"; } +.bi-bookmark-fill::before { content: "\f199"; } +.bi-bookmark-heart-fill::before { content: "\f19a"; } +.bi-bookmark-heart::before { content: "\f19b"; } +.bi-bookmark-plus-fill::before { content: "\f19c"; } +.bi-bookmark-plus::before { content: "\f19d"; } +.bi-bookmark-star-fill::before { content: "\f19e"; } +.bi-bookmark-star::before { content: "\f19f"; } +.bi-bookmark-x-fill::before { content: "\f1a0"; } +.bi-bookmark-x::before { content: "\f1a1"; } +.bi-bookmark::before { content: "\f1a2"; } +.bi-bookmarks-fill::before { content: "\f1a3"; } +.bi-bookmarks::before { content: "\f1a4"; } +.bi-bookshelf::before { content: "\f1a5"; } +.bi-bootstrap-fill::before { content: "\f1a6"; } +.bi-bootstrap-reboot::before { content: "\f1a7"; } +.bi-bootstrap::before { content: "\f1a8"; } +.bi-border-all::before { content: "\f1a9"; } +.bi-border-bottom::before { content: "\f1aa"; } +.bi-border-center::before { content: "\f1ab"; } +.bi-border-inner::before { content: "\f1ac"; } +.bi-border-left::before { content: "\f1ad"; } +.bi-border-middle::before { content: "\f1ae"; } +.bi-border-outer::before { content: "\f1af"; } +.bi-border-right::before { content: "\f1b0"; } +.bi-border-style::before { content: "\f1b1"; } +.bi-border-top::before { content: "\f1b2"; } +.bi-border-width::before { content: "\f1b3"; } +.bi-border::before { content: "\f1b4"; } +.bi-bounding-box-circles::before { content: "\f1b5"; } +.bi-bounding-box::before { content: "\f1b6"; } +.bi-box-arrow-down-left::before { content: "\f1b7"; } +.bi-box-arrow-down-right::before { content: "\f1b8"; } +.bi-box-arrow-down::before { content: "\f1b9"; } +.bi-box-arrow-in-down-left::before { content: "\f1ba"; } +.bi-box-arrow-in-down-right::before { content: "\f1bb"; } +.bi-box-arrow-in-down::before { content: "\f1bc"; } +.bi-box-arrow-in-left::before { content: "\f1bd"; } +.bi-box-arrow-in-right::before { content: "\f1be"; } +.bi-box-arrow-in-up-left::before { content: "\f1bf"; } +.bi-box-arrow-in-up-right::before { content: "\f1c0"; } +.bi-box-arrow-in-up::before { content: "\f1c1"; } +.bi-box-arrow-left::before { content: "\f1c2"; } +.bi-box-arrow-right::before { content: "\f1c3"; } +.bi-box-arrow-up-left::before { content: "\f1c4"; } +.bi-box-arrow-up-right::before { content: "\f1c5"; } +.bi-box-arrow-up::before { content: "\f1c6"; } +.bi-box-seam::before { content: "\f1c7"; } +.bi-box::before { content: "\f1c8"; } +.bi-braces::before { content: "\f1c9"; } +.bi-bricks::before { content: "\f1ca"; } +.bi-briefcase-fill::before { content: "\f1cb"; } +.bi-briefcase::before { content: "\f1cc"; } +.bi-brightness-alt-high-fill::before { content: "\f1cd"; } +.bi-brightness-alt-high::before { content: "\f1ce"; } +.bi-brightness-alt-low-fill::before { content: "\f1cf"; } +.bi-brightness-alt-low::before { content: "\f1d0"; } +.bi-brightness-high-fill::before { content: "\f1d1"; } +.bi-brightness-high::before { content: "\f1d2"; } +.bi-brightness-low-fill::before { content: "\f1d3"; } +.bi-brightness-low::before { content: "\f1d4"; } +.bi-broadcast-pin::before { content: "\f1d5"; } +.bi-broadcast::before { content: "\f1d6"; } +.bi-brush-fill::before { content: "\f1d7"; } +.bi-brush::before { content: "\f1d8"; } +.bi-bucket-fill::before { content: "\f1d9"; } +.bi-bucket::before { content: "\f1da"; } +.bi-bug-fill::before { content: "\f1db"; } +.bi-bug::before { content: "\f1dc"; } +.bi-building::before { content: "\f1dd"; } +.bi-bullseye::before { content: "\f1de"; } +.bi-calculator-fill::before { content: "\f1df"; } +.bi-calculator::before { content: "\f1e0"; } +.bi-calendar-check-fill::before { content: "\f1e1"; } +.bi-calendar-check::before { content: "\f1e2"; } +.bi-calendar-date-fill::before { content: "\f1e3"; } +.bi-calendar-date::before { content: "\f1e4"; } +.bi-calendar-day-fill::before { content: "\f1e5"; } +.bi-calendar-day::before { content: "\f1e6"; } +.bi-calendar-event-fill::before { content: "\f1e7"; } +.bi-calendar-event::before { content: "\f1e8"; } +.bi-calendar-fill::before { content: "\f1e9"; } +.bi-calendar-minus-fill::before { content: "\f1ea"; } +.bi-calendar-minus::before { content: "\f1eb"; } +.bi-calendar-month-fill::before { content: "\f1ec"; } +.bi-calendar-month::before { content: "\f1ed"; } +.bi-calendar-plus-fill::before { content: "\f1ee"; } +.bi-calendar-plus::before { content: "\f1ef"; } +.bi-calendar-range-fill::before { content: "\f1f0"; } +.bi-calendar-range::before { content: "\f1f1"; } +.bi-calendar-week-fill::before { content: "\f1f2"; } +.bi-calendar-week::before { content: "\f1f3"; } +.bi-calendar-x-fill::before { content: "\f1f4"; } +.bi-calendar-x::before { content: "\f1f5"; } +.bi-calendar::before { content: "\f1f6"; } +.bi-calendar2-check-fill::before { content: "\f1f7"; } +.bi-calendar2-check::before { content: "\f1f8"; } +.bi-calendar2-date-fill::before { content: "\f1f9"; } +.bi-calendar2-date::before { content: "\f1fa"; } +.bi-calendar2-day-fill::before { content: "\f1fb"; } +.bi-calendar2-day::before { content: "\f1fc"; } +.bi-calendar2-event-fill::before { content: "\f1fd"; } +.bi-calendar2-event::before { content: "\f1fe"; } +.bi-calendar2-fill::before { content: "\f1ff"; } +.bi-calendar2-minus-fill::before { content: "\f200"; } +.bi-calendar2-minus::before { content: "\f201"; } +.bi-calendar2-month-fill::before { content: "\f202"; } +.bi-calendar2-month::before { content: "\f203"; } +.bi-calendar2-plus-fill::before { content: "\f204"; } +.bi-calendar2-plus::before { content: "\f205"; } +.bi-calendar2-range-fill::before { content: "\f206"; } +.bi-calendar2-range::before { content: "\f207"; } +.bi-calendar2-week-fill::before { content: "\f208"; } +.bi-calendar2-week::before { content: "\f209"; } +.bi-calendar2-x-fill::before { content: "\f20a"; } +.bi-calendar2-x::before { content: "\f20b"; } +.bi-calendar2::before { content: "\f20c"; } +.bi-calendar3-event-fill::before { content: "\f20d"; } +.bi-calendar3-event::before { content: "\f20e"; } +.bi-calendar3-fill::before { content: "\f20f"; } +.bi-calendar3-range-fill::before { content: "\f210"; } +.bi-calendar3-range::before { content: "\f211"; } +.bi-calendar3-week-fill::before { content: "\f212"; } +.bi-calendar3-week::before { content: "\f213"; } +.bi-calendar3::before { content: "\f214"; } +.bi-calendar4-event::before { content: "\f215"; } +.bi-calendar4-range::before { content: "\f216"; } +.bi-calendar4-week::before { content: "\f217"; } +.bi-calendar4::before { content: "\f218"; } +.bi-camera-fill::before { content: "\f219"; } +.bi-camera-reels-fill::before { content: "\f21a"; } +.bi-camera-reels::before { content: "\f21b"; } +.bi-camera-video-fill::before { content: "\f21c"; } +.bi-camera-video-off-fill::before { content: "\f21d"; } +.bi-camera-video-off::before { content: "\f21e"; } +.bi-camera-video::before { content: "\f21f"; } +.bi-camera::before { content: "\f220"; } +.bi-camera2::before { content: "\f221"; } +.bi-capslock-fill::before { content: "\f222"; } +.bi-capslock::before { content: "\f223"; } +.bi-card-checklist::before { content: "\f224"; } +.bi-card-heading::before { content: "\f225"; } +.bi-card-image::before { content: "\f226"; } +.bi-card-list::before { content: "\f227"; } +.bi-card-text::before { content: "\f228"; } +.bi-caret-down-fill::before { content: "\f229"; } +.bi-caret-down-square-fill::before { content: "\f22a"; } +.bi-caret-down-square::before { content: "\f22b"; } +.bi-caret-down::before { content: "\f22c"; } +.bi-caret-left-fill::before { content: "\f22d"; } +.bi-caret-left-square-fill::before { content: "\f22e"; } +.bi-caret-left-square::before { content: "\f22f"; } +.bi-caret-left::before { content: "\f230"; } +.bi-caret-right-fill::before { content: "\f231"; } +.bi-caret-right-square-fill::before { content: "\f232"; } +.bi-caret-right-square::before { content: "\f233"; } +.bi-caret-right::before { content: "\f234"; } +.bi-caret-up-fill::before { content: "\f235"; } +.bi-caret-up-square-fill::before { content: "\f236"; } +.bi-caret-up-square::before { content: "\f237"; } +.bi-caret-up::before { content: "\f238"; } +.bi-cart-check-fill::before { content: "\f239"; } +.bi-cart-check::before { content: "\f23a"; } +.bi-cart-dash-fill::before { content: "\f23b"; } +.bi-cart-dash::before { content: "\f23c"; } +.bi-cart-fill::before { content: "\f23d"; } +.bi-cart-plus-fill::before { content: "\f23e"; } +.bi-cart-plus::before { content: "\f23f"; } +.bi-cart-x-fill::before { content: "\f240"; } +.bi-cart-x::before { content: "\f241"; } +.bi-cart::before { content: "\f242"; } +.bi-cart2::before { content: "\f243"; } +.bi-cart3::before { content: "\f244"; } +.bi-cart4::before { content: "\f245"; } +.bi-cash-stack::before { content: "\f246"; } +.bi-cash::before { content: "\f247"; } +.bi-cast::before { content: "\f248"; } +.bi-chat-dots-fill::before { content: "\f249"; } +.bi-chat-dots::before { content: "\f24a"; } +.bi-chat-fill::before { content: "\f24b"; } +.bi-chat-left-dots-fill::before { content: "\f24c"; } +.bi-chat-left-dots::before { content: "\f24d"; } +.bi-chat-left-fill::before { content: "\f24e"; } +.bi-chat-left-quote-fill::before { content: "\f24f"; } +.bi-chat-left-quote::before { content: "\f250"; } +.bi-chat-left-text-fill::before { content: "\f251"; } +.bi-chat-left-text::before { content: "\f252"; } +.bi-chat-left::before { content: "\f253"; } +.bi-chat-quote-fill::before { content: "\f254"; } +.bi-chat-quote::before { content: "\f255"; } +.bi-chat-right-dots-fill::before { content: "\f256"; } +.bi-chat-right-dots::before { content: "\f257"; } +.bi-chat-right-fill::before { content: "\f258"; } +.bi-chat-right-quote-fill::before { content: "\f259"; } +.bi-chat-right-quote::before { content: "\f25a"; } +.bi-chat-right-text-fill::before { content: "\f25b"; } +.bi-chat-right-text::before { content: "\f25c"; } +.bi-chat-right::before { content: "\f25d"; } +.bi-chat-square-dots-fill::before { content: "\f25e"; } +.bi-chat-square-dots::before { content: "\f25f"; } +.bi-chat-square-fill::before { content: "\f260"; } +.bi-chat-square-quote-fill::before { content: "\f261"; } +.bi-chat-square-quote::before { content: "\f262"; } +.bi-chat-square-text-fill::before { content: "\f263"; } +.bi-chat-square-text::before { content: "\f264"; } +.bi-chat-square::before { content: "\f265"; } +.bi-chat-text-fill::before { content: "\f266"; } +.bi-chat-text::before { content: "\f267"; } +.bi-chat::before { content: "\f268"; } +.bi-check-all::before { content: "\f269"; } +.bi-check-circle-fill::before { content: "\f26a"; } +.bi-check-circle::before { content: "\f26b"; } +.bi-check-square-fill::before { content: "\f26c"; } +.bi-check-square::before { content: "\f26d"; } +.bi-check::before { content: "\f26e"; } +.bi-check2-all::before { content: "\f26f"; } +.bi-check2-circle::before { content: "\f270"; } +.bi-check2-square::before { content: "\f271"; } +.bi-check2::before { content: "\f272"; } +.bi-chevron-bar-contract::before { content: "\f273"; } +.bi-chevron-bar-down::before { content: "\f274"; } +.bi-chevron-bar-expand::before { content: "\f275"; } +.bi-chevron-bar-left::before { content: "\f276"; } +.bi-chevron-bar-right::before { content: "\f277"; } +.bi-chevron-bar-up::before { content: "\f278"; } +.bi-chevron-compact-down::before { content: "\f279"; } +.bi-chevron-compact-left::before { content: "\f27a"; } +.bi-chevron-compact-right::before { content: "\f27b"; } +.bi-chevron-compact-up::before { content: "\f27c"; } +.bi-chevron-contract::before { content: "\f27d"; } +.bi-chevron-double-down::before { content: "\f27e"; } +.bi-chevron-double-left::before { content: "\f27f"; } +.bi-chevron-double-right::before { content: "\f280"; } +.bi-chevron-double-up::before { content: "\f281"; } +.bi-chevron-down::before { content: "\f282"; } +.bi-chevron-expand::before { content: "\f283"; } +.bi-chevron-left::before { content: "\f284"; } +.bi-chevron-right::before { content: "\f285"; } +.bi-chevron-up::before { content: "\f286"; } +.bi-circle-fill::before { content: "\f287"; } +.bi-circle-half::before { content: "\f288"; } +.bi-circle-square::before { content: "\f289"; } +.bi-circle::before { content: "\f28a"; } +.bi-clipboard-check::before { content: "\f28b"; } +.bi-clipboard-data::before { content: "\f28c"; } +.bi-clipboard-minus::before { content: "\f28d"; } +.bi-clipboard-plus::before { content: "\f28e"; } +.bi-clipboard-x::before { content: "\f28f"; } +.bi-clipboard::before { content: "\f290"; } +.bi-clock-fill::before { content: "\f291"; } +.bi-clock-history::before { content: "\f292"; } +.bi-clock::before { content: "\f293"; } +.bi-cloud-arrow-down-fill::before { content: "\f294"; } +.bi-cloud-arrow-down::before { content: "\f295"; } +.bi-cloud-arrow-up-fill::before { content: "\f296"; } +.bi-cloud-arrow-up::before { content: "\f297"; } +.bi-cloud-check-fill::before { content: "\f298"; } +.bi-cloud-check::before { content: "\f299"; } +.bi-cloud-download-fill::before { content: "\f29a"; } +.bi-cloud-download::before { content: "\f29b"; } +.bi-cloud-drizzle-fill::before { content: "\f29c"; } +.bi-cloud-drizzle::before { content: "\f29d"; } +.bi-cloud-fill::before { content: "\f29e"; } +.bi-cloud-fog-fill::before { content: "\f29f"; } +.bi-cloud-fog::before { content: "\f2a0"; } +.bi-cloud-fog2-fill::before { content: "\f2a1"; } +.bi-cloud-fog2::before { content: "\f2a2"; } +.bi-cloud-hail-fill::before { content: "\f2a3"; } +.bi-cloud-hail::before { content: "\f2a4"; } +.bi-cloud-haze-1::before { content: "\f2a5"; } +.bi-cloud-haze-fill::before { content: "\f2a6"; } +.bi-cloud-haze::before { content: "\f2a7"; } +.bi-cloud-haze2-fill::before { content: "\f2a8"; } +.bi-cloud-lightning-fill::before { content: "\f2a9"; } +.bi-cloud-lightning-rain-fill::before { content: "\f2aa"; } +.bi-cloud-lightning-rain::before { content: "\f2ab"; } +.bi-cloud-lightning::before { content: "\f2ac"; } +.bi-cloud-minus-fill::before { content: "\f2ad"; } +.bi-cloud-minus::before { content: "\f2ae"; } +.bi-cloud-moon-fill::before { content: "\f2af"; } +.bi-cloud-moon::before { content: "\f2b0"; } +.bi-cloud-plus-fill::before { content: "\f2b1"; } +.bi-cloud-plus::before { content: "\f2b2"; } +.bi-cloud-rain-fill::before { content: "\f2b3"; } +.bi-cloud-rain-heavy-fill::before { content: "\f2b4"; } +.bi-cloud-rain-heavy::before { content: "\f2b5"; } +.bi-cloud-rain::before { content: "\f2b6"; } +.bi-cloud-slash-fill::before { content: "\f2b7"; } +.bi-cloud-slash::before { content: "\f2b8"; } +.bi-cloud-sleet-fill::before { content: "\f2b9"; } +.bi-cloud-sleet::before { content: "\f2ba"; } +.bi-cloud-snow-fill::before { content: "\f2bb"; } +.bi-cloud-snow::before { content: "\f2bc"; } +.bi-cloud-sun-fill::before { content: "\f2bd"; } +.bi-cloud-sun::before { content: "\f2be"; } +.bi-cloud-upload-fill::before { content: "\f2bf"; } +.bi-cloud-upload::before { content: "\f2c0"; } +.bi-cloud::before { content: "\f2c1"; } +.bi-clouds-fill::before { content: "\f2c2"; } +.bi-clouds::before { content: "\f2c3"; } +.bi-cloudy-fill::before { content: "\f2c4"; } +.bi-cloudy::before { content: "\f2c5"; } +.bi-code-slash::before { content: "\f2c6"; } +.bi-code-square::before { content: "\f2c7"; } +.bi-code::before { content: "\f2c8"; } +.bi-collection-fill::before { content: "\f2c9"; } +.bi-collection-play-fill::before { content: "\f2ca"; } +.bi-collection-play::before { content: "\f2cb"; } +.bi-collection::before { content: "\f2cc"; } +.bi-columns-gap::before { content: "\f2cd"; } +.bi-columns::before { content: "\f2ce"; } +.bi-command::before { content: "\f2cf"; } +.bi-compass-fill::before { content: "\f2d0"; } +.bi-compass::before { content: "\f2d1"; } +.bi-cone-striped::before { content: "\f2d2"; } +.bi-cone::before { content: "\f2d3"; } +.bi-controller::before { content: "\f2d4"; } +.bi-cpu-fill::before { content: "\f2d5"; } +.bi-cpu::before { content: "\f2d6"; } +.bi-credit-card-2-back-fill::before { content: "\f2d7"; } +.bi-credit-card-2-back::before { content: "\f2d8"; } +.bi-credit-card-2-front-fill::before { content: "\f2d9"; } +.bi-credit-card-2-front::before { content: "\f2da"; } +.bi-credit-card-fill::before { content: "\f2db"; } +.bi-credit-card::before { content: "\f2dc"; } +.bi-crop::before { content: "\f2dd"; } +.bi-cup-fill::before { content: "\f2de"; } +.bi-cup-straw::before { content: "\f2df"; } +.bi-cup::before { content: "\f2e0"; } +.bi-cursor-fill::before { content: "\f2e1"; } +.bi-cursor-text::before { content: "\f2e2"; } +.bi-cursor::before { content: "\f2e3"; } +.bi-dash-circle-dotted::before { content: "\f2e4"; } +.bi-dash-circle-fill::before { content: "\f2e5"; } +.bi-dash-circle::before { content: "\f2e6"; } +.bi-dash-square-dotted::before { content: "\f2e7"; } +.bi-dash-square-fill::before { content: "\f2e8"; } +.bi-dash-square::before { content: "\f2e9"; } +.bi-dash::before { content: "\f2ea"; } +.bi-diagram-2-fill::before { content: "\f2eb"; } +.bi-diagram-2::before { content: "\f2ec"; } +.bi-diagram-3-fill::before { content: "\f2ed"; } +.bi-diagram-3::before { content: "\f2ee"; } +.bi-diamond-fill::before { content: "\f2ef"; } +.bi-diamond-half::before { content: "\f2f0"; } +.bi-diamond::before { content: "\f2f1"; } +.bi-dice-1-fill::before { content: "\f2f2"; } +.bi-dice-1::before { content: "\f2f3"; } +.bi-dice-2-fill::before { content: "\f2f4"; } +.bi-dice-2::before { content: "\f2f5"; } +.bi-dice-3-fill::before { content: "\f2f6"; } +.bi-dice-3::before { content: "\f2f7"; } +.bi-dice-4-fill::before { content: "\f2f8"; } +.bi-dice-4::before { content: "\f2f9"; } +.bi-dice-5-fill::before { content: "\f2fa"; } +.bi-dice-5::before { content: "\f2fb"; } +.bi-dice-6-fill::before { content: "\f2fc"; } +.bi-dice-6::before { content: "\f2fd"; } +.bi-disc-fill::before { content: "\f2fe"; } +.bi-disc::before { content: "\f2ff"; } +.bi-discord::before { content: "\f300"; } +.bi-display-fill::before { content: "\f301"; } +.bi-display::before { content: "\f302"; } +.bi-distribute-horizontal::before { content: "\f303"; } +.bi-distribute-vertical::before { content: "\f304"; } +.bi-door-closed-fill::before { content: "\f305"; } +.bi-door-closed::before { content: "\f306"; } +.bi-door-open-fill::before { content: "\f307"; } +.bi-door-open::before { content: "\f308"; } +.bi-dot::before { content: "\f309"; } +.bi-download::before { content: "\f30a"; } +.bi-droplet-fill::before { content: "\f30b"; } +.bi-droplet-half::before { content: "\f30c"; } +.bi-droplet::before { content: "\f30d"; } +.bi-earbuds::before { content: "\f30e"; } +.bi-easel-fill::before { content: "\f30f"; } +.bi-easel::before { content: "\f310"; } +.bi-egg-fill::before { content: "\f311"; } +.bi-egg-fried::before { content: "\f312"; } +.bi-egg::before { content: "\f313"; } +.bi-eject-fill::before { content: "\f314"; } +.bi-eject::before { content: "\f315"; } +.bi-emoji-angry-fill::before { content: "\f316"; } +.bi-emoji-angry::before { content: "\f317"; } +.bi-emoji-dizzy-fill::before { content: "\f318"; } +.bi-emoji-dizzy::before { content: "\f319"; } +.bi-emoji-expressionless-fill::before { content: "\f31a"; } +.bi-emoji-expressionless::before { content: "\f31b"; } +.bi-emoji-frown-fill::before { content: "\f31c"; } +.bi-emoji-frown::before { content: "\f31d"; } +.bi-emoji-heart-eyes-fill::before { content: "\f31e"; } +.bi-emoji-heart-eyes::before { content: "\f31f"; } +.bi-emoji-laughing-fill::before { content: "\f320"; } +.bi-emoji-laughing::before { content: "\f321"; } +.bi-emoji-neutral-fill::before { content: "\f322"; } +.bi-emoji-neutral::before { content: "\f323"; } +.bi-emoji-smile-fill::before { content: "\f324"; } +.bi-emoji-smile-upside-down-fill::before { content: "\f325"; } +.bi-emoji-smile-upside-down::before { content: "\f326"; } +.bi-emoji-smile::before { content: "\f327"; } +.bi-emoji-sunglasses-fill::before { content: "\f328"; } +.bi-emoji-sunglasses::before { content: "\f329"; } +.bi-emoji-wink-fill::before { content: "\f32a"; } +.bi-emoji-wink::before { content: "\f32b"; } +.bi-envelope-fill::before { content: "\f32c"; } +.bi-envelope-open-fill::before { content: "\f32d"; } +.bi-envelope-open::before { content: "\f32e"; } +.bi-envelope::before { content: "\f32f"; } +.bi-eraser-fill::before { content: "\f330"; } +.bi-eraser::before { content: "\f331"; } +.bi-exclamation-circle-fill::before { content: "\f332"; } +.bi-exclamation-circle::before { content: "\f333"; } +.bi-exclamation-diamond-fill::before { content: "\f334"; } +.bi-exclamation-diamond::before { content: "\f335"; } +.bi-exclamation-octagon-fill::before { content: "\f336"; } +.bi-exclamation-octagon::before { content: "\f337"; } +.bi-exclamation-square-fill::before { content: "\f338"; } +.bi-exclamation-square::before { content: "\f339"; } +.bi-exclamation-triangle-fill::before { content: "\f33a"; } +.bi-exclamation-triangle::before { content: "\f33b"; } +.bi-exclamation::before { content: "\f33c"; } +.bi-exclude::before { content: "\f33d"; } +.bi-eye-fill::before { content: "\f33e"; } +.bi-eye-slash-fill::before { content: "\f33f"; } +.bi-eye-slash::before { content: "\f340"; } +.bi-eye::before { content: "\f341"; } +.bi-eyedropper::before { content: "\f342"; } +.bi-eyeglasses::before { content: "\f343"; } +.bi-facebook::before { content: "\f344"; } +.bi-file-arrow-down-fill::before { content: "\f345"; } +.bi-file-arrow-down::before { content: "\f346"; } +.bi-file-arrow-up-fill::before { content: "\f347"; } +.bi-file-arrow-up::before { content: "\f348"; } +.bi-file-bar-graph-fill::before { content: "\f349"; } +.bi-file-bar-graph::before { content: "\f34a"; } +.bi-file-binary-fill::before { content: "\f34b"; } +.bi-file-binary::before { content: "\f34c"; } +.bi-file-break-fill::before { content: "\f34d"; } +.bi-file-break::before { content: "\f34e"; } +.bi-file-check-fill::before { content: "\f34f"; } +.bi-file-check::before { content: "\f350"; } +.bi-file-code-fill::before { content: "\f351"; } +.bi-file-code::before { content: "\f352"; } +.bi-file-diff-fill::before { content: "\f353"; } +.bi-file-diff::before { content: "\f354"; } +.bi-file-earmark-arrow-down-fill::before { content: "\f355"; } +.bi-file-earmark-arrow-down::before { content: "\f356"; } +.bi-file-earmark-arrow-up-fill::before { content: "\f357"; } +.bi-file-earmark-arrow-up::before { content: "\f358"; } +.bi-file-earmark-bar-graph-fill::before { content: "\f359"; } +.bi-file-earmark-bar-graph::before { content: "\f35a"; } +.bi-file-earmark-binary-fill::before { content: "\f35b"; } +.bi-file-earmark-binary::before { content: "\f35c"; } +.bi-file-earmark-break-fill::before { content: "\f35d"; } +.bi-file-earmark-break::before { content: "\f35e"; } +.bi-file-earmark-check-fill::before { content: "\f35f"; } +.bi-file-earmark-check::before { content: "\f360"; } +.bi-file-earmark-code-fill::before { content: "\f361"; } +.bi-file-earmark-code::before { content: "\f362"; } +.bi-file-earmark-diff-fill::before { content: "\f363"; } +.bi-file-earmark-diff::before { content: "\f364"; } +.bi-file-earmark-easel-fill::before { content: "\f365"; } +.bi-file-earmark-easel::before { content: "\f366"; } +.bi-file-earmark-excel-fill::before { content: "\f367"; } +.bi-file-earmark-excel::before { content: "\f368"; } +.bi-file-earmark-fill::before { content: "\f369"; } +.bi-file-earmark-font-fill::before { content: "\f36a"; } +.bi-file-earmark-font::before { content: "\f36b"; } +.bi-file-earmark-image-fill::before { content: "\f36c"; } +.bi-file-earmark-image::before { content: "\f36d"; } +.bi-file-earmark-lock-fill::before { content: "\f36e"; } +.bi-file-earmark-lock::before { content: "\f36f"; } +.bi-file-earmark-lock2-fill::before { content: "\f370"; } +.bi-file-earmark-lock2::before { content: "\f371"; } +.bi-file-earmark-medical-fill::before { content: "\f372"; } +.bi-file-earmark-medical::before { content: "\f373"; } +.bi-file-earmark-minus-fill::before { content: "\f374"; } +.bi-file-earmark-minus::before { content: "\f375"; } +.bi-file-earmark-music-fill::before { content: "\f376"; } +.bi-file-earmark-music::before { content: "\f377"; } +.bi-file-earmark-person-fill::before { content: "\f378"; } +.bi-file-earmark-person::before { content: "\f379"; } +.bi-file-earmark-play-fill::before { content: "\f37a"; } +.bi-file-earmark-play::before { content: "\f37b"; } +.bi-file-earmark-plus-fill::before { content: "\f37c"; } +.bi-file-earmark-plus::before { content: "\f37d"; } +.bi-file-earmark-post-fill::before { content: "\f37e"; } +.bi-file-earmark-post::before { content: "\f37f"; } +.bi-file-earmark-ppt-fill::before { content: "\f380"; } +.bi-file-earmark-ppt::before { content: "\f381"; } +.bi-file-earmark-richtext-fill::before { content: "\f382"; } +.bi-file-earmark-richtext::before { content: "\f383"; } +.bi-file-earmark-ruled-fill::before { content: "\f384"; } +.bi-file-earmark-ruled::before { content: "\f385"; } +.bi-file-earmark-slides-fill::before { content: "\f386"; } +.bi-file-earmark-slides::before { content: "\f387"; } +.bi-file-earmark-spreadsheet-fill::before { content: "\f388"; } +.bi-file-earmark-spreadsheet::before { content: "\f389"; } +.bi-file-earmark-text-fill::before { content: "\f38a"; } +.bi-file-earmark-text::before { content: "\f38b"; } +.bi-file-earmark-word-fill::before { content: "\f38c"; } +.bi-file-earmark-word::before { content: "\f38d"; } +.bi-file-earmark-x-fill::before { content: "\f38e"; } +.bi-file-earmark-x::before { content: "\f38f"; } +.bi-file-earmark-zip-fill::before { content: "\f390"; } +.bi-file-earmark-zip::before { content: "\f391"; } +.bi-file-earmark::before { content: "\f392"; } +.bi-file-easel-fill::before { content: "\f393"; } +.bi-file-easel::before { content: "\f394"; } +.bi-file-excel-fill::before { content: "\f395"; } +.bi-file-excel::before { content: "\f396"; } +.bi-file-fill::before { content: "\f397"; } +.bi-file-font-fill::before { content: "\f398"; } +.bi-file-font::before { content: "\f399"; } +.bi-file-image-fill::before { content: "\f39a"; } +.bi-file-image::before { content: "\f39b"; } +.bi-file-lock-fill::before { content: "\f39c"; } +.bi-file-lock::before { content: "\f39d"; } +.bi-file-lock2-fill::before { content: "\f39e"; } +.bi-file-lock2::before { content: "\f39f"; } +.bi-file-medical-fill::before { content: "\f3a0"; } +.bi-file-medical::before { content: "\f3a1"; } +.bi-file-minus-fill::before { content: "\f3a2"; } +.bi-file-minus::before { content: "\f3a3"; } +.bi-file-music-fill::before { content: "\f3a4"; } +.bi-file-music::before { content: "\f3a5"; } +.bi-file-person-fill::before { content: "\f3a6"; } +.bi-file-person::before { content: "\f3a7"; } +.bi-file-play-fill::before { content: "\f3a8"; } +.bi-file-play::before { content: "\f3a9"; } +.bi-file-plus-fill::before { content: "\f3aa"; } +.bi-file-plus::before { content: "\f3ab"; } +.bi-file-post-fill::before { content: "\f3ac"; } +.bi-file-post::before { content: "\f3ad"; } +.bi-file-ppt-fill::before { content: "\f3ae"; } +.bi-file-ppt::before { content: "\f3af"; } +.bi-file-richtext-fill::before { content: "\f3b0"; } +.bi-file-richtext::before { content: "\f3b1"; } +.bi-file-ruled-fill::before { content: "\f3b2"; } +.bi-file-ruled::before { content: "\f3b3"; } +.bi-file-slides-fill::before { content: "\f3b4"; } +.bi-file-slides::before { content: "\f3b5"; } +.bi-file-spreadsheet-fill::before { content: "\f3b6"; } +.bi-file-spreadsheet::before { content: "\f3b7"; } +.bi-file-text-fill::before { content: "\f3b8"; } +.bi-file-text::before { content: "\f3b9"; } +.bi-file-word-fill::before { content: "\f3ba"; } +.bi-file-word::before { content: "\f3bb"; } +.bi-file-x-fill::before { content: "\f3bc"; } +.bi-file-x::before { content: "\f3bd"; } +.bi-file-zip-fill::before { content: "\f3be"; } +.bi-file-zip::before { content: "\f3bf"; } +.bi-file::before { content: "\f3c0"; } +.bi-files-alt::before { content: "\f3c1"; } +.bi-files::before { content: "\f3c2"; } +.bi-film::before { content: "\f3c3"; } +.bi-filter-circle-fill::before { content: "\f3c4"; } +.bi-filter-circle::before { content: "\f3c5"; } +.bi-filter-left::before { content: "\f3c6"; } +.bi-filter-right::before { content: "\f3c7"; } +.bi-filter-square-fill::before { content: "\f3c8"; } +.bi-filter-square::before { content: "\f3c9"; } +.bi-filter::before { content: "\f3ca"; } +.bi-flag-fill::before { content: "\f3cb"; } +.bi-flag::before { content: "\f3cc"; } +.bi-flower1::before { content: "\f3cd"; } +.bi-flower2::before { content: "\f3ce"; } +.bi-flower3::before { content: "\f3cf"; } +.bi-folder-check::before { content: "\f3d0"; } +.bi-folder-fill::before { content: "\f3d1"; } +.bi-folder-minus::before { content: "\f3d2"; } +.bi-folder-plus::before { content: "\f3d3"; } +.bi-folder-symlink-fill::before { content: "\f3d4"; } +.bi-folder-symlink::before { content: "\f3d5"; } +.bi-folder-x::before { content: "\f3d6"; } +.bi-folder::before { content: "\f3d7"; } +.bi-folder2-open::before { content: "\f3d8"; } +.bi-folder2::before { content: "\f3d9"; } +.bi-fonts::before { content: "\f3da"; } +.bi-forward-fill::before { content: "\f3db"; } +.bi-forward::before { content: "\f3dc"; } +.bi-front::before { content: "\f3dd"; } +.bi-fullscreen-exit::before { content: "\f3de"; } +.bi-fullscreen::before { content: "\f3df"; } +.bi-funnel-fill::before { content: "\f3e0"; } +.bi-funnel::before { content: "\f3e1"; } +.bi-gear-fill::before { content: "\f3e2"; } +.bi-gear-wide-connected::before { content: "\f3e3"; } +.bi-gear-wide::before { content: "\f3e4"; } +.bi-gear::before { content: "\f3e5"; } +.bi-gem::before { content: "\f3e6"; } +.bi-geo-alt-fill::before { content: "\f3e7"; } +.bi-geo-alt::before { content: "\f3e8"; } +.bi-geo-fill::before { content: "\f3e9"; } +.bi-geo::before { content: "\f3ea"; } +.bi-gift-fill::before { content: "\f3eb"; } +.bi-gift::before { content: "\f3ec"; } +.bi-github::before { content: "\f3ed"; } +.bi-globe::before { content: "\f3ee"; } +.bi-globe2::before { content: "\f3ef"; } +.bi-google::before { content: "\f3f0"; } +.bi-graph-down::before { content: "\f3f1"; } +.bi-graph-up::before { content: "\f3f2"; } +.bi-grid-1x2-fill::before { content: "\f3f3"; } +.bi-grid-1x2::before { content: "\f3f4"; } +.bi-grid-3x2-gap-fill::before { content: "\f3f5"; } +.bi-grid-3x2-gap::before { content: "\f3f6"; } +.bi-grid-3x2::before { content: "\f3f7"; } +.bi-grid-3x3-gap-fill::before { content: "\f3f8"; } +.bi-grid-3x3-gap::before { content: "\f3f9"; } +.bi-grid-3x3::before { content: "\f3fa"; } +.bi-grid-fill::before { content: "\f3fb"; } +.bi-grid::before { content: "\f3fc"; } +.bi-grip-horizontal::before { content: "\f3fd"; } +.bi-grip-vertical::before { content: "\f3fe"; } +.bi-hammer::before { content: "\f3ff"; } +.bi-hand-index-fill::before { content: "\f400"; } +.bi-hand-index-thumb-fill::before { content: "\f401"; } +.bi-hand-index-thumb::before { content: "\f402"; } +.bi-hand-index::before { content: "\f403"; } +.bi-hand-thumbs-down-fill::before { content: "\f404"; } +.bi-hand-thumbs-down::before { content: "\f405"; } +.bi-hand-thumbs-up-fill::before { content: "\f406"; } +.bi-hand-thumbs-up::before { content: "\f407"; } +.bi-handbag-fill::before { content: "\f408"; } +.bi-handbag::before { content: "\f409"; } +.bi-hash::before { content: "\f40a"; } +.bi-hdd-fill::before { content: "\f40b"; } +.bi-hdd-network-fill::before { content: "\f40c"; } +.bi-hdd-network::before { content: "\f40d"; } +.bi-hdd-rack-fill::before { content: "\f40e"; } +.bi-hdd-rack::before { content: "\f40f"; } +.bi-hdd-stack-fill::before { content: "\f410"; } +.bi-hdd-stack::before { content: "\f411"; } +.bi-hdd::before { content: "\f412"; } +.bi-headphones::before { content: "\f413"; } +.bi-headset::before { content: "\f414"; } +.bi-heart-fill::before { content: "\f415"; } +.bi-heart-half::before { content: "\f416"; } +.bi-heart::before { content: "\f417"; } +.bi-heptagon-fill::before { content: "\f418"; } +.bi-heptagon-half::before { content: "\f419"; } +.bi-heptagon::before { content: "\f41a"; } +.bi-hexagon-fill::before { content: "\f41b"; } +.bi-hexagon-half::before { content: "\f41c"; } +.bi-hexagon::before { content: "\f41d"; } +.bi-hourglass-bottom::before { content: "\f41e"; } +.bi-hourglass-split::before { content: "\f41f"; } +.bi-hourglass-top::before { content: "\f420"; } +.bi-hourglass::before { content: "\f421"; } +.bi-house-door-fill::before { content: "\f422"; } +.bi-house-door::before { content: "\f423"; } +.bi-house-fill::before { content: "\f424"; } +.bi-house::before { content: "\f425"; } +.bi-hr::before { content: "\f426"; } +.bi-hurricane::before { content: "\f427"; } +.bi-image-alt::before { content: "\f428"; } +.bi-image-fill::before { content: "\f429"; } +.bi-image::before { content: "\f42a"; } +.bi-images::before { content: "\f42b"; } +.bi-inbox-fill::before { content: "\f42c"; } +.bi-inbox::before { content: "\f42d"; } +.bi-inboxes-fill::before { content: "\f42e"; } +.bi-inboxes::before { content: "\f42f"; } +.bi-info-circle-fill::before { content: "\f430"; } +.bi-info-circle::before { content: "\f431"; } +.bi-info-square-fill::before { content: "\f432"; } +.bi-info-square::before { content: "\f433"; } +.bi-info::before { content: "\f434"; } +.bi-input-cursor-text::before { content: "\f435"; } +.bi-input-cursor::before { content: "\f436"; } +.bi-instagram::before { content: "\f437"; } +.bi-intersect::before { content: "\f438"; } +.bi-journal-album::before { content: "\f439"; } +.bi-journal-arrow-down::before { content: "\f43a"; } +.bi-journal-arrow-up::before { content: "\f43b"; } +.bi-journal-bookmark-fill::before { content: "\f43c"; } +.bi-journal-bookmark::before { content: "\f43d"; } +.bi-journal-check::before { content: "\f43e"; } +.bi-journal-code::before { content: "\f43f"; } +.bi-journal-medical::before { content: "\f440"; } +.bi-journal-minus::before { content: "\f441"; } +.bi-journal-plus::before { content: "\f442"; } +.bi-journal-richtext::before { content: "\f443"; } +.bi-journal-text::before { content: "\f444"; } +.bi-journal-x::before { content: "\f445"; } +.bi-journal::before { content: "\f446"; } +.bi-journals::before { content: "\f447"; } +.bi-joystick::before { content: "\f448"; } +.bi-justify-left::before { content: "\f449"; } +.bi-justify-right::before { content: "\f44a"; } +.bi-justify::before { content: "\f44b"; } +.bi-kanban-fill::before { content: "\f44c"; } +.bi-kanban::before { content: "\f44d"; } +.bi-key-fill::before { content: "\f44e"; } +.bi-key::before { content: "\f44f"; } +.bi-keyboard-fill::before { content: "\f450"; } +.bi-keyboard::before { content: "\f451"; } +.bi-ladder::before { content: "\f452"; } +.bi-lamp-fill::before { content: "\f453"; } +.bi-lamp::before { content: "\f454"; } +.bi-laptop-fill::before { content: "\f455"; } +.bi-laptop::before { content: "\f456"; } +.bi-layer-backward::before { content: "\f457"; } +.bi-layer-forward::before { content: "\f458"; } +.bi-layers-fill::before { content: "\f459"; } +.bi-layers-half::before { content: "\f45a"; } +.bi-layers::before { content: "\f45b"; } +.bi-layout-sidebar-inset-reverse::before { content: "\f45c"; } +.bi-layout-sidebar-inset::before { content: "\f45d"; } +.bi-layout-sidebar-reverse::before { content: "\f45e"; } +.bi-layout-sidebar::before { content: "\f45f"; } +.bi-layout-split::before { content: "\f460"; } +.bi-layout-text-sidebar-reverse::before { content: "\f461"; } +.bi-layout-text-sidebar::before { content: "\f462"; } +.bi-layout-text-window-reverse::before { content: "\f463"; } +.bi-layout-text-window::before { content: "\f464"; } +.bi-layout-three-columns::before { content: "\f465"; } +.bi-layout-wtf::before { content: "\f466"; } +.bi-life-preserver::before { content: "\f467"; } +.bi-lightbulb-fill::before { content: "\f468"; } +.bi-lightbulb-off-fill::before { content: "\f469"; } +.bi-lightbulb-off::before { content: "\f46a"; } +.bi-lightbulb::before { content: "\f46b"; } +.bi-lightning-charge-fill::before { content: "\f46c"; } +.bi-lightning-charge::before { content: "\f46d"; } +.bi-lightning-fill::before { content: "\f46e"; } +.bi-lightning::before { content: "\f46f"; } +.bi-link-45deg::before { content: "\f470"; } +.bi-link::before { content: "\f471"; } +.bi-linkedin::before { content: "\f472"; } +.bi-list-check::before { content: "\f473"; } +.bi-list-nested::before { content: "\f474"; } +.bi-list-ol::before { content: "\f475"; } +.bi-list-stars::before { content: "\f476"; } +.bi-list-task::before { content: "\f477"; } +.bi-list-ul::before { content: "\f478"; } +.bi-list::before { content: "\f479"; } +.bi-lock-fill::before { content: "\f47a"; } +.bi-lock::before { content: "\f47b"; } +.bi-mailbox::before { content: "\f47c"; } +.bi-mailbox2::before { content: "\f47d"; } +.bi-map-fill::before { content: "\f47e"; } +.bi-map::before { content: "\f47f"; } +.bi-markdown-fill::before { content: "\f480"; } +.bi-markdown::before { content: "\f481"; } +.bi-mask::before { content: "\f482"; } +.bi-megaphone-fill::before { content: "\f483"; } +.bi-megaphone::before { content: "\f484"; } +.bi-menu-app-fill::before { content: "\f485"; } +.bi-menu-app::before { content: "\f486"; } +.bi-menu-button-fill::before { content: "\f487"; } +.bi-menu-button-wide-fill::before { content: "\f488"; } +.bi-menu-button-wide::before { content: "\f489"; } +.bi-menu-button::before { content: "\f48a"; } +.bi-menu-down::before { content: "\f48b"; } +.bi-menu-up::before { content: "\f48c"; } +.bi-mic-fill::before { content: "\f48d"; } +.bi-mic-mute-fill::before { content: "\f48e"; } +.bi-mic-mute::before { content: "\f48f"; } +.bi-mic::before { content: "\f490"; } +.bi-minecart-loaded::before { content: "\f491"; } +.bi-minecart::before { content: "\f492"; } +.bi-moisture::before { content: "\f493"; } +.bi-moon-fill::before { content: "\f494"; } +.bi-moon-stars-fill::before { content: "\f495"; } +.bi-moon-stars::before { content: "\f496"; } +.bi-moon::before { content: "\f497"; } +.bi-mouse-fill::before { content: "\f498"; } +.bi-mouse::before { content: "\f499"; } +.bi-mouse2-fill::before { content: "\f49a"; } +.bi-mouse2::before { content: "\f49b"; } +.bi-mouse3-fill::before { content: "\f49c"; } +.bi-mouse3::before { content: "\f49d"; } +.bi-music-note-beamed::before { content: "\f49e"; } +.bi-music-note-list::before { content: "\f49f"; } +.bi-music-note::before { content: "\f4a0"; } +.bi-music-player-fill::before { content: "\f4a1"; } +.bi-music-player::before { content: "\f4a2"; } +.bi-newspaper::before { content: "\f4a3"; } +.bi-node-minus-fill::before { content: "\f4a4"; } +.bi-node-minus::before { content: "\f4a5"; } +.bi-node-plus-fill::before { content: "\f4a6"; } +.bi-node-plus::before { content: "\f4a7"; } +.bi-nut-fill::before { content: "\f4a8"; } +.bi-nut::before { content: "\f4a9"; } +.bi-octagon-fill::before { content: "\f4aa"; } +.bi-octagon-half::before { content: "\f4ab"; } +.bi-octagon::before { content: "\f4ac"; } +.bi-option::before { content: "\f4ad"; } +.bi-outlet::before { content: "\f4ae"; } +.bi-paint-bucket::before { content: "\f4af"; } +.bi-palette-fill::before { content: "\f4b0"; } +.bi-palette::before { content: "\f4b1"; } +.bi-palette2::before { content: "\f4b2"; } +.bi-paperclip::before { content: "\f4b3"; } +.bi-paragraph::before { content: "\f4b4"; } +.bi-patch-check-fill::before { content: "\f4b5"; } +.bi-patch-check::before { content: "\f4b6"; } +.bi-patch-exclamation-fill::before { content: "\f4b7"; } +.bi-patch-exclamation::before { content: "\f4b8"; } +.bi-patch-minus-fill::before { content: "\f4b9"; } +.bi-patch-minus::before { content: "\f4ba"; } +.bi-patch-plus-fill::before { content: "\f4bb"; } +.bi-patch-plus::before { content: "\f4bc"; } +.bi-patch-question-fill::before { content: "\f4bd"; } +.bi-patch-question::before { content: "\f4be"; } +.bi-pause-btn-fill::before { content: "\f4bf"; } +.bi-pause-btn::before { content: "\f4c0"; } +.bi-pause-circle-fill::before { content: "\f4c1"; } +.bi-pause-circle::before { content: "\f4c2"; } +.bi-pause-fill::before { content: "\f4c3"; } +.bi-pause::before { content: "\f4c4"; } +.bi-peace-fill::before { content: "\f4c5"; } +.bi-peace::before { content: "\f4c6"; } +.bi-pen-fill::before { content: "\f4c7"; } +.bi-pen::before { content: "\f4c8"; } +.bi-pencil-fill::before { content: "\f4c9"; } +.bi-pencil-square::before { content: "\f4ca"; } +.bi-pencil::before { content: "\f4cb"; } +.bi-pentagon-fill::before { content: "\f4cc"; } +.bi-pentagon-half::before { content: "\f4cd"; } +.bi-pentagon::before { content: "\f4ce"; } +.bi-people-fill::before { content: "\f4cf"; } +.bi-people::before { content: "\f4d0"; } +.bi-percent::before { content: "\f4d1"; } +.bi-person-badge-fill::before { content: "\f4d2"; } +.bi-person-badge::before { content: "\f4d3"; } +.bi-person-bounding-box::before { content: "\f4d4"; } +.bi-person-check-fill::before { content: "\f4d5"; } +.bi-person-check::before { content: "\f4d6"; } +.bi-person-circle::before { content: "\f4d7"; } +.bi-person-dash-fill::before { content: "\f4d8"; } +.bi-person-dash::before { content: "\f4d9"; } +.bi-person-fill::before { content: "\f4da"; } +.bi-person-lines-fill::before { content: "\f4db"; } +.bi-person-plus-fill::before { content: "\f4dc"; } +.bi-person-plus::before { content: "\f4dd"; } +.bi-person-square::before { content: "\f4de"; } +.bi-person-x-fill::before { content: "\f4df"; } +.bi-person-x::before { content: "\f4e0"; } +.bi-person::before { content: "\f4e1"; } +.bi-phone-fill::before { content: "\f4e2"; } +.bi-phone-landscape-fill::before { content: "\f4e3"; } +.bi-phone-landscape::before { content: "\f4e4"; } +.bi-phone-vibrate-fill::before { content: "\f4e5"; } +.bi-phone-vibrate::before { content: "\f4e6"; } +.bi-phone::before { content: "\f4e7"; } +.bi-pie-chart-fill::before { content: "\f4e8"; } +.bi-pie-chart::before { content: "\f4e9"; } +.bi-pin-angle-fill::before { content: "\f4ea"; } +.bi-pin-angle::before { content: "\f4eb"; } +.bi-pin-fill::before { content: "\f4ec"; } +.bi-pin::before { content: "\f4ed"; } +.bi-pip-fill::before { content: "\f4ee"; } +.bi-pip::before { content: "\f4ef"; } +.bi-play-btn-fill::before { content: "\f4f0"; } +.bi-play-btn::before { content: "\f4f1"; } +.bi-play-circle-fill::before { content: "\f4f2"; } +.bi-play-circle::before { content: "\f4f3"; } +.bi-play-fill::before { content: "\f4f4"; } +.bi-play::before { content: "\f4f5"; } +.bi-plug-fill::before { content: "\f4f6"; } +.bi-plug::before { content: "\f4f7"; } +.bi-plus-circle-dotted::before { content: "\f4f8"; } +.bi-plus-circle-fill::before { content: "\f4f9"; } +.bi-plus-circle::before { content: "\f4fa"; } +.bi-plus-square-dotted::before { content: "\f4fb"; } +.bi-plus-square-fill::before { content: "\f4fc"; } +.bi-plus-square::before { content: "\f4fd"; } +.bi-plus::before { content: "\f4fe"; } +.bi-power::before { content: "\f4ff"; } +.bi-printer-fill::before { content: "\f500"; } +.bi-printer::before { content: "\f501"; } +.bi-puzzle-fill::before { content: "\f502"; } +.bi-puzzle::before { content: "\f503"; } +.bi-question-circle-fill::before { content: "\f504"; } +.bi-question-circle::before { content: "\f505"; } +.bi-question-diamond-fill::before { content: "\f506"; } +.bi-question-diamond::before { content: "\f507"; } +.bi-question-octagon-fill::before { content: "\f508"; } +.bi-question-octagon::before { content: "\f509"; } +.bi-question-square-fill::before { content: "\f50a"; } +.bi-question-square::before { content: "\f50b"; } +.bi-question::before { content: "\f50c"; } +.bi-rainbow::before { content: "\f50d"; } +.bi-receipt-cutoff::before { content: "\f50e"; } +.bi-receipt::before { content: "\f50f"; } +.bi-reception-0::before { content: "\f510"; } +.bi-reception-1::before { content: "\f511"; } +.bi-reception-2::before { content: "\f512"; } +.bi-reception-3::before { content: "\f513"; } +.bi-reception-4::before { content: "\f514"; } +.bi-record-btn-fill::before { content: "\f515"; } +.bi-record-btn::before { content: "\f516"; } +.bi-record-circle-fill::before { content: "\f517"; } +.bi-record-circle::before { content: "\f518"; } +.bi-record-fill::before { content: "\f519"; } +.bi-record::before { content: "\f51a"; } +.bi-record2-fill::before { content: "\f51b"; } +.bi-record2::before { content: "\f51c"; } +.bi-reply-all-fill::before { content: "\f51d"; } +.bi-reply-all::before { content: "\f51e"; } +.bi-reply-fill::before { content: "\f51f"; } +.bi-reply::before { content: "\f520"; } +.bi-rss-fill::before { content: "\f521"; } +.bi-rss::before { content: "\f522"; } +.bi-rulers::before { content: "\f523"; } +.bi-save-fill::before { content: "\f524"; } +.bi-save::before { content: "\f525"; } +.bi-save2-fill::before { content: "\f526"; } +.bi-save2::before { content: "\f527"; } +.bi-scissors::before { content: "\f528"; } +.bi-screwdriver::before { content: "\f529"; } +.bi-search::before { content: "\f52a"; } +.bi-segmented-nav::before { content: "\f52b"; } +.bi-server::before { content: "\f52c"; } +.bi-share-fill::before { content: "\f52d"; } +.bi-share::before { content: "\f52e"; } +.bi-shield-check::before { content: "\f52f"; } +.bi-shield-exclamation::before { content: "\f530"; } +.bi-shield-fill-check::before { content: "\f531"; } +.bi-shield-fill-exclamation::before { content: "\f532"; } +.bi-shield-fill-minus::before { content: "\f533"; } +.bi-shield-fill-plus::before { content: "\f534"; } +.bi-shield-fill-x::before { content: "\f535"; } +.bi-shield-fill::before { content: "\f536"; } +.bi-shield-lock-fill::before { content: "\f537"; } +.bi-shield-lock::before { content: "\f538"; } +.bi-shield-minus::before { content: "\f539"; } +.bi-shield-plus::before { content: "\f53a"; } +.bi-shield-shaded::before { content: "\f53b"; } +.bi-shield-slash-fill::before { content: "\f53c"; } +.bi-shield-slash::before { content: "\f53d"; } +.bi-shield-x::before { content: "\f53e"; } +.bi-shield::before { content: "\f53f"; } +.bi-shift-fill::before { content: "\f540"; } +.bi-shift::before { content: "\f541"; } +.bi-shop-window::before { content: "\f542"; } +.bi-shop::before { content: "\f543"; } +.bi-shuffle::before { content: "\f544"; } +.bi-signpost-2-fill::before { content: "\f545"; } +.bi-signpost-2::before { content: "\f546"; } +.bi-signpost-fill::before { content: "\f547"; } +.bi-signpost-split-fill::before { content: "\f548"; } +.bi-signpost-split::before { content: "\f549"; } +.bi-signpost::before { content: "\f54a"; } +.bi-sim-fill::before { content: "\f54b"; } +.bi-sim::before { content: "\f54c"; } +.bi-skip-backward-btn-fill::before { content: "\f54d"; } +.bi-skip-backward-btn::before { content: "\f54e"; } +.bi-skip-backward-circle-fill::before { content: "\f54f"; } +.bi-skip-backward-circle::before { content: "\f550"; } +.bi-skip-backward-fill::before { content: "\f551"; } +.bi-skip-backward::before { content: "\f552"; } +.bi-skip-end-btn-fill::before { content: "\f553"; } +.bi-skip-end-btn::before { content: "\f554"; } +.bi-skip-end-circle-fill::before { content: "\f555"; } +.bi-skip-end-circle::before { content: "\f556"; } +.bi-skip-end-fill::before { content: "\f557"; } +.bi-skip-end::before { content: "\f558"; } +.bi-skip-forward-btn-fill::before { content: "\f559"; } +.bi-skip-forward-btn::before { content: "\f55a"; } +.bi-skip-forward-circle-fill::before { content: "\f55b"; } +.bi-skip-forward-circle::before { content: "\f55c"; } +.bi-skip-forward-fill::before { content: "\f55d"; } +.bi-skip-forward::before { content: "\f55e"; } +.bi-skip-start-btn-fill::before { content: "\f55f"; } +.bi-skip-start-btn::before { content: "\f560"; } +.bi-skip-start-circle-fill::before { content: "\f561"; } +.bi-skip-start-circle::before { content: "\f562"; } +.bi-skip-start-fill::before { content: "\f563"; } +.bi-skip-start::before { content: "\f564"; } +.bi-slack::before { content: "\f565"; } +.bi-slash-circle-fill::before { content: "\f566"; } +.bi-slash-circle::before { content: "\f567"; } +.bi-slash-square-fill::before { content: "\f568"; } +.bi-slash-square::before { content: "\f569"; } +.bi-slash::before { content: "\f56a"; } +.bi-sliders::before { content: "\f56b"; } +.bi-smartwatch::before { content: "\f56c"; } +.bi-snow::before { content: "\f56d"; } +.bi-snow2::before { content: "\f56e"; } +.bi-snow3::before { content: "\f56f"; } +.bi-sort-alpha-down-alt::before { content: "\f570"; } +.bi-sort-alpha-down::before { content: "\f571"; } +.bi-sort-alpha-up-alt::before { content: "\f572"; } +.bi-sort-alpha-up::before { content: "\f573"; } +.bi-sort-down-alt::before { content: "\f574"; } +.bi-sort-down::before { content: "\f575"; } +.bi-sort-numeric-down-alt::before { content: "\f576"; } +.bi-sort-numeric-down::before { content: "\f577"; } +.bi-sort-numeric-up-alt::before { content: "\f578"; } +.bi-sort-numeric-up::before { content: "\f579"; } +.bi-sort-up-alt::before { content: "\f57a"; } +.bi-sort-up::before { content: "\f57b"; } +.bi-soundwave::before { content: "\f57c"; } +.bi-speaker-fill::before { content: "\f57d"; } +.bi-speaker::before { content: "\f57e"; } +.bi-speedometer::before { content: "\f57f"; } +.bi-speedometer2::before { content: "\f580"; } +.bi-spellcheck::before { content: "\f581"; } +.bi-square-fill::before { content: "\f582"; } +.bi-square-half::before { content: "\f583"; } +.bi-square::before { content: "\f584"; } +.bi-stack::before { content: "\f585"; } +.bi-star-fill::before { content: "\f586"; } +.bi-star-half::before { content: "\f587"; } +.bi-star::before { content: "\f588"; } +.bi-stars::before { content: "\f589"; } +.bi-stickies-fill::before { content: "\f58a"; } +.bi-stickies::before { content: "\f58b"; } +.bi-sticky-fill::before { content: "\f58c"; } +.bi-sticky::before { content: "\f58d"; } +.bi-stop-btn-fill::before { content: "\f58e"; } +.bi-stop-btn::before { content: "\f58f"; } +.bi-stop-circle-fill::before { content: "\f590"; } +.bi-stop-circle::before { content: "\f591"; } +.bi-stop-fill::before { content: "\f592"; } +.bi-stop::before { content: "\f593"; } +.bi-stoplights-fill::before { content: "\f594"; } +.bi-stoplights::before { content: "\f595"; } +.bi-stopwatch-fill::before { content: "\f596"; } +.bi-stopwatch::before { content: "\f597"; } +.bi-subtract::before { content: "\f598"; } +.bi-suit-club-fill::before { content: "\f599"; } +.bi-suit-club::before { content: "\f59a"; } +.bi-suit-diamond-fill::before { content: "\f59b"; } +.bi-suit-diamond::before { content: "\f59c"; } +.bi-suit-heart-fill::before { content: "\f59d"; } +.bi-suit-heart::before { content: "\f59e"; } +.bi-suit-spade-fill::before { content: "\f59f"; } +.bi-suit-spade::before { content: "\f5a0"; } +.bi-sun-fill::before { content: "\f5a1"; } +.bi-sun::before { content: "\f5a2"; } +.bi-sunglasses::before { content: "\f5a3"; } +.bi-sunrise-fill::before { content: "\f5a4"; } +.bi-sunrise::before { content: "\f5a5"; } +.bi-sunset-fill::before { content: "\f5a6"; } +.bi-sunset::before { content: "\f5a7"; } +.bi-symmetry-horizontal::before { content: "\f5a8"; } +.bi-symmetry-vertical::before { content: "\f5a9"; } +.bi-table::before { content: "\f5aa"; } +.bi-tablet-fill::before { content: "\f5ab"; } +.bi-tablet-landscape-fill::before { content: "\f5ac"; } +.bi-tablet-landscape::before { content: "\f5ad"; } +.bi-tablet::before { content: "\f5ae"; } +.bi-tag-fill::before { content: "\f5af"; } +.bi-tag::before { content: "\f5b0"; } +.bi-tags-fill::before { content: "\f5b1"; } +.bi-tags::before { content: "\f5b2"; } +.bi-telegram::before { content: "\f5b3"; } +.bi-telephone-fill::before { content: "\f5b4"; } +.bi-telephone-forward-fill::before { content: "\f5b5"; } +.bi-telephone-forward::before { content: "\f5b6"; } +.bi-telephone-inbound-fill::before { content: "\f5b7"; } +.bi-telephone-inbound::before { content: "\f5b8"; } +.bi-telephone-minus-fill::before { content: "\f5b9"; } +.bi-telephone-minus::before { content: "\f5ba"; } +.bi-telephone-outbound-fill::before { content: "\f5bb"; } +.bi-telephone-outbound::before { content: "\f5bc"; } +.bi-telephone-plus-fill::before { content: "\f5bd"; } +.bi-telephone-plus::before { content: "\f5be"; } +.bi-telephone-x-fill::before { content: "\f5bf"; } +.bi-telephone-x::before { content: "\f5c0"; } +.bi-telephone::before { content: "\f5c1"; } +.bi-terminal-fill::before { content: "\f5c2"; } +.bi-terminal::before { content: "\f5c3"; } +.bi-text-center::before { content: "\f5c4"; } +.bi-text-indent-left::before { content: "\f5c5"; } +.bi-text-indent-right::before { content: "\f5c6"; } +.bi-text-left::before { content: "\f5c7"; } +.bi-text-paragraph::before { content: "\f5c8"; } +.bi-text-right::before { content: "\f5c9"; } +.bi-textarea-resize::before { content: "\f5ca"; } +.bi-textarea-t::before { content: "\f5cb"; } +.bi-textarea::before { content: "\f5cc"; } +.bi-thermometer-half::before { content: "\f5cd"; } +.bi-thermometer-high::before { content: "\f5ce"; } +.bi-thermometer-low::before { content: "\f5cf"; } +.bi-thermometer-snow::before { content: "\f5d0"; } +.bi-thermometer-sun::before { content: "\f5d1"; } +.bi-thermometer::before { content: "\f5d2"; } +.bi-three-dots-vertical::before { content: "\f5d3"; } +.bi-three-dots::before { content: "\f5d4"; } +.bi-toggle-off::before { content: "\f5d5"; } +.bi-toggle-on::before { content: "\f5d6"; } +.bi-toggle2-off::before { content: "\f5d7"; } +.bi-toggle2-on::before { content: "\f5d8"; } +.bi-toggles::before { content: "\f5d9"; } +.bi-toggles2::before { content: "\f5da"; } +.bi-tools::before { content: "\f5db"; } +.bi-tornado::before { content: "\f5dc"; } +.bi-trash-fill::before { content: "\f5dd"; } +.bi-trash::before { content: "\f5de"; } +.bi-trash2-fill::before { content: "\f5df"; } +.bi-trash2::before { content: "\f5e0"; } +.bi-tree-fill::before { content: "\f5e1"; } +.bi-tree::before { content: "\f5e2"; } +.bi-triangle-fill::before { content: "\f5e3"; } +.bi-triangle-half::before { content: "\f5e4"; } +.bi-triangle::before { content: "\f5e5"; } +.bi-trophy-fill::before { content: "\f5e6"; } +.bi-trophy::before { content: "\f5e7"; } +.bi-tropical-storm::before { content: "\f5e8"; } +.bi-truck-flatbed::before { content: "\f5e9"; } +.bi-truck::before { content: "\f5ea"; } +.bi-tsunami::before { content: "\f5eb"; } +.bi-tv-fill::before { content: "\f5ec"; } +.bi-tv::before { content: "\f5ed"; } +.bi-twitch::before { content: "\f5ee"; } +.bi-twitter::before { content: "\f5ef"; } +.bi-type-bold::before { content: "\f5f0"; } +.bi-type-h1::before { content: "\f5f1"; } +.bi-type-h2::before { content: "\f5f2"; } +.bi-type-h3::before { content: "\f5f3"; } +.bi-type-italic::before { content: "\f5f4"; } +.bi-type-strikethrough::before { content: "\f5f5"; } +.bi-type-underline::before { content: "\f5f6"; } +.bi-type::before { content: "\f5f7"; } +.bi-ui-checks-grid::before { content: "\f5f8"; } +.bi-ui-checks::before { content: "\f5f9"; } +.bi-ui-radios-grid::before { content: "\f5fa"; } +.bi-ui-radios::before { content: "\f5fb"; } +.bi-umbrella-fill::before { content: "\f5fc"; } +.bi-umbrella::before { content: "\f5fd"; } +.bi-union::before { content: "\f5fe"; } +.bi-unlock-fill::before { content: "\f5ff"; } +.bi-unlock::before { content: "\f600"; } +.bi-upc-scan::before { content: "\f601"; } +.bi-upc::before { content: "\f602"; } +.bi-upload::before { content: "\f603"; } +.bi-vector-pen::before { content: "\f604"; } +.bi-view-list::before { content: "\f605"; } +.bi-view-stacked::before { content: "\f606"; } +.bi-vinyl-fill::before { content: "\f607"; } +.bi-vinyl::before { content: "\f608"; } +.bi-voicemail::before { content: "\f609"; } +.bi-volume-down-fill::before { content: "\f60a"; } +.bi-volume-down::before { content: "\f60b"; } +.bi-volume-mute-fill::before { content: "\f60c"; } +.bi-volume-mute::before { content: "\f60d"; } +.bi-volume-off-fill::before { content: "\f60e"; } +.bi-volume-off::before { content: "\f60f"; } +.bi-volume-up-fill::before { content: "\f610"; } +.bi-volume-up::before { content: "\f611"; } +.bi-vr::before { content: "\f612"; } +.bi-wallet-fill::before { content: "\f613"; } +.bi-wallet::before { content: "\f614"; } +.bi-wallet2::before { content: "\f615"; } +.bi-watch::before { content: "\f616"; } +.bi-water::before { content: "\f617"; } +.bi-whatsapp::before { content: "\f618"; } +.bi-wifi-1::before { content: "\f619"; } +.bi-wifi-2::before { content: "\f61a"; } +.bi-wifi-off::before { content: "\f61b"; } +.bi-wifi::before { content: "\f61c"; } +.bi-wind::before { content: "\f61d"; } +.bi-window-dock::before { content: "\f61e"; } +.bi-window-sidebar::before { content: "\f61f"; } +.bi-window::before { content: "\f620"; } +.bi-wrench::before { content: "\f621"; } +.bi-x-circle-fill::before { content: "\f622"; } +.bi-x-circle::before { content: "\f623"; } +.bi-x-diamond-fill::before { content: "\f624"; } +.bi-x-diamond::before { content: "\f625"; } +.bi-x-octagon-fill::before { content: "\f626"; } +.bi-x-octagon::before { content: "\f627"; } +.bi-x-square-fill::before { content: "\f628"; } +.bi-x-square::before { content: "\f629"; } +.bi-x::before { content: "\f62a"; } +.bi-youtube::before { content: "\f62b"; } +.bi-zoom-in::before { content: "\f62c"; } +.bi-zoom-out::before { content: "\f62d"; } +.bi-bank::before { content: "\f62e"; } +.bi-bank2::before { content: "\f62f"; } +.bi-bell-slash-fill::before { content: "\f630"; } +.bi-bell-slash::before { content: "\f631"; } +.bi-cash-coin::before { content: "\f632"; } +.bi-check-lg::before { content: "\f633"; } +.bi-coin::before { content: "\f634"; } +.bi-currency-bitcoin::before { content: "\f635"; } +.bi-currency-dollar::before { content: "\f636"; } +.bi-currency-euro::before { content: "\f637"; } +.bi-currency-exchange::before { content: "\f638"; } +.bi-currency-pound::before { content: "\f639"; } +.bi-currency-yen::before { content: "\f63a"; } +.bi-dash-lg::before { content: "\f63b"; } +.bi-exclamation-lg::before { content: "\f63c"; } +.bi-file-earmark-pdf-fill::before { content: "\f63d"; } +.bi-file-earmark-pdf::before { content: "\f63e"; } +.bi-file-pdf-fill::before { content: "\f63f"; } +.bi-file-pdf::before { content: "\f640"; } +.bi-gender-ambiguous::before { content: "\f641"; } +.bi-gender-female::before { content: "\f642"; } +.bi-gender-male::before { content: "\f643"; } +.bi-gender-trans::before { content: "\f644"; } +.bi-headset-vr::before { content: "\f645"; } +.bi-info-lg::before { content: "\f646"; } +.bi-mastodon::before { content: "\f647"; } +.bi-messenger::before { content: "\f648"; } +.bi-piggy-bank-fill::before { content: "\f649"; } +.bi-piggy-bank::before { content: "\f64a"; } +.bi-pin-map-fill::before { content: "\f64b"; } +.bi-pin-map::before { content: "\f64c"; } +.bi-plus-lg::before { content: "\f64d"; } +.bi-question-lg::before { content: "\f64e"; } +.bi-recycle::before { content: "\f64f"; } +.bi-reddit::before { content: "\f650"; } +.bi-safe-fill::before { content: "\f651"; } +.bi-safe2-fill::before { content: "\f652"; } +.bi-safe2::before { content: "\f653"; } +.bi-sd-card-fill::before { content: "\f654"; } +.bi-sd-card::before { content: "\f655"; } +.bi-skype::before { content: "\f656"; } +.bi-slash-lg::before { content: "\f657"; } +.bi-translate::before { content: "\f658"; } +.bi-x-lg::before { content: "\f659"; } +.bi-safe::before { content: "\f65a"; } +.bi-apple::before { content: "\f65b"; } +.bi-microsoft::before { content: "\f65d"; } +.bi-windows::before { content: "\f65e"; } +.bi-behance::before { content: "\f65c"; } +.bi-dribbble::before { content: "\f65f"; } +.bi-line::before { content: "\f660"; } +.bi-medium::before { content: "\f661"; } +.bi-paypal::before { content: "\f662"; } +.bi-pinterest::before { content: "\f663"; } +.bi-signal::before { content: "\f664"; } +.bi-snapchat::before { content: "\f665"; } +.bi-spotify::before { content: "\f666"; } +.bi-stack-overflow::before { content: "\f667"; } +.bi-strava::before { content: "\f668"; } +.bi-wordpress::before { content: "\f669"; } +.bi-vimeo::before { content: "\f66a"; } +.bi-activity::before { content: "\f66b"; } +.bi-easel2-fill::before { content: "\f66c"; } +.bi-easel2::before { content: "\f66d"; } +.bi-easel3-fill::before { content: "\f66e"; } +.bi-easel3::before { content: "\f66f"; } +.bi-fan::before { content: "\f670"; } +.bi-fingerprint::before { content: "\f671"; } +.bi-graph-down-arrow::before { content: "\f672"; } +.bi-graph-up-arrow::before { content: "\f673"; } +.bi-hypnotize::before { content: "\f674"; } +.bi-magic::before { content: "\f675"; } +.bi-person-rolodex::before { content: "\f676"; } +.bi-person-video::before { content: "\f677"; } +.bi-person-video2::before { content: "\f678"; } +.bi-person-video3::before { content: "\f679"; } +.bi-person-workspace::before { content: "\f67a"; } +.bi-radioactive::before { content: "\f67b"; } +.bi-webcam-fill::before { content: "\f67c"; } +.bi-webcam::before { content: "\f67d"; } +.bi-yin-yang::before { content: "\f67e"; } +.bi-bandaid-fill::before { content: "\f680"; } +.bi-bandaid::before { content: "\f681"; } +.bi-bluetooth::before { content: "\f682"; } +.bi-body-text::before { content: "\f683"; } +.bi-boombox::before { content: "\f684"; } +.bi-boxes::before { content: "\f685"; } +.bi-dpad-fill::before { content: "\f686"; } +.bi-dpad::before { content: "\f687"; } +.bi-ear-fill::before { content: "\f688"; } +.bi-ear::before { content: "\f689"; } +.bi-envelope-check-1::before { content: "\f68a"; } +.bi-envelope-check-fill::before { content: "\f68b"; } +.bi-envelope-check::before { content: "\f68c"; } +.bi-envelope-dash-1::before { content: "\f68d"; } +.bi-envelope-dash-fill::before { content: "\f68e"; } +.bi-envelope-dash::before { content: "\f68f"; } +.bi-envelope-exclamation-1::before { content: "\f690"; } +.bi-envelope-exclamation-fill::before { content: "\f691"; } +.bi-envelope-exclamation::before { content: "\f692"; } +.bi-envelope-plus-fill::before { content: "\f693"; } +.bi-envelope-plus::before { content: "\f694"; } +.bi-envelope-slash-1::before { content: "\f695"; } +.bi-envelope-slash-fill::before { content: "\f696"; } +.bi-envelope-slash::before { content: "\f697"; } +.bi-envelope-x-1::before { content: "\f698"; } +.bi-envelope-x-fill::before { content: "\f699"; } +.bi-envelope-x::before { content: "\f69a"; } +.bi-explicit-fill::before { content: "\f69b"; } +.bi-explicit::before { content: "\f69c"; } +.bi-git::before { content: "\f69d"; } +.bi-infinity::before { content: "\f69e"; } +.bi-list-columns-reverse::before { content: "\f69f"; } +.bi-list-columns::before { content: "\f6a0"; } +.bi-meta::before { content: "\f6a1"; } +.bi-mortorboard-fill::before { content: "\f6a2"; } +.bi-mortorboard::before { content: "\f6a3"; } +.bi-nintendo-switch::before { content: "\f6a4"; } +.bi-pc-display-horizontal::before { content: "\f6a5"; } +.bi-pc-display::before { content: "\f6a6"; } +.bi-pc-horizontal::before { content: "\f6a7"; } +.bi-pc::before { content: "\f6a8"; } +.bi-playstation::before { content: "\f6a9"; } +.bi-plus-slash-minus::before { content: "\f6aa"; } +.bi-projector-fill::before { content: "\f6ab"; } +.bi-projector::before { content: "\f6ac"; } +.bi-qr-code-scan::before { content: "\f6ad"; } +.bi-qr-code::before { content: "\f6ae"; } +.bi-quora::before { content: "\f6af"; } +.bi-quote::before { content: "\f6b0"; } +.bi-robot::before { content: "\f6b1"; } +.bi-send-check-fill::before { content: "\f6b2"; } +.bi-send-check::before { content: "\f6b3"; } +.bi-send-dash-fill::before { content: "\f6b4"; } +.bi-send-dash::before { content: "\f6b5"; } +.bi-send-exclamation-1::before { content: "\f6b6"; } +.bi-send-exclamation-fill::before { content: "\f6b7"; } +.bi-send-exclamation::before { content: "\f6b8"; } +.bi-send-fill::before { content: "\f6b9"; } +.bi-send-plus-fill::before { content: "\f6ba"; } +.bi-send-plus::before { content: "\f6bb"; } +.bi-send-slash-fill::before { content: "\f6bc"; } +.bi-send-slash::before { content: "\f6bd"; } +.bi-send-x-fill::before { content: "\f6be"; } +.bi-send-x::before { content: "\f6bf"; } +.bi-send::before { content: "\f6c0"; } +.bi-steam::before { content: "\f6c1"; } +.bi-terminal-dash-1::before { content: "\f6c2"; } +.bi-terminal-dash::before { content: "\f6c3"; } +.bi-terminal-plus::before { content: "\f6c4"; } +.bi-terminal-split::before { content: "\f6c5"; } +.bi-ticket-detailed-fill::before { content: "\f6c6"; } +.bi-ticket-detailed::before { content: "\f6c7"; } +.bi-ticket-fill::before { content: "\f6c8"; } +.bi-ticket-perforated-fill::before { content: "\f6c9"; } +.bi-ticket-perforated::before { content: "\f6ca"; } +.bi-ticket::before { content: "\f6cb"; } +.bi-tiktok::before { content: "\f6cc"; } +.bi-window-dash::before { content: "\f6cd"; } +.bi-window-desktop::before { content: "\f6ce"; } +.bi-window-fullscreen::before { content: "\f6cf"; } +.bi-window-plus::before { content: "\f6d0"; } +.bi-window-split::before { content: "\f6d1"; } +.bi-window-stack::before { content: "\f6d2"; } +.bi-window-x::before { content: "\f6d3"; } +.bi-xbox::before { content: "\f6d4"; } +.bi-ethernet::before { content: "\f6d5"; } +.bi-hdmi-fill::before { content: "\f6d6"; } +.bi-hdmi::before { content: "\f6d7"; } +.bi-usb-c-fill::before { content: "\f6d8"; } +.bi-usb-c::before { content: "\f6d9"; } +.bi-usb-fill::before { content: "\f6da"; } +.bi-usb-plug-fill::before { content: "\f6db"; } +.bi-usb-plug::before { content: "\f6dc"; } +.bi-usb-symbol::before { content: "\f6dd"; } +.bi-usb::before { content: "\f6de"; } +.bi-boombox-fill::before { content: "\f6df"; } +.bi-displayport-1::before { content: "\f6e0"; } +.bi-displayport::before { content: "\f6e1"; } +.bi-gpu-card::before { content: "\f6e2"; } +.bi-memory::before { content: "\f6e3"; } +.bi-modem-fill::before { content: "\f6e4"; } +.bi-modem::before { content: "\f6e5"; } +.bi-motherboard-fill::before { content: "\f6e6"; } +.bi-motherboard::before { content: "\f6e7"; } +.bi-optical-audio-fill::before { content: "\f6e8"; } +.bi-optical-audio::before { content: "\f6e9"; } +.bi-pci-card::before { content: "\f6ea"; } +.bi-router-fill::before { content: "\f6eb"; } +.bi-router::before { content: "\f6ec"; } +.bi-ssd-fill::before { content: "\f6ed"; } +.bi-ssd::before { content: "\f6ee"; } +.bi-thunderbolt-fill::before { content: "\f6ef"; } +.bi-thunderbolt::before { content: "\f6f0"; } +.bi-usb-drive-fill::before { content: "\f6f1"; } +.bi-usb-drive::before { content: "\f6f2"; } +.bi-usb-micro-fill::before { content: "\f6f3"; } +.bi-usb-micro::before { content: "\f6f4"; } +.bi-usb-mini-fill::before { content: "\f6f5"; } +.bi-usb-mini::before { content: "\f6f6"; } +.bi-cloud-haze2::before { content: "\f6f7"; } +.bi-device-hdd-fill::before { content: "\f6f8"; } +.bi-device-hdd::before { content: "\f6f9"; } +.bi-device-ssd-fill::before { content: "\f6fa"; } +.bi-device-ssd::before { content: "\f6fb"; } +.bi-displayport-fill::before { content: "\f6fc"; } +.bi-mortarboard-fill::before { content: "\f6fd"; } +.bi-mortarboard::before { content: "\f6fe"; } +.bi-terminal-x::before { content: "\f6ff"; } +.bi-arrow-through-heart-fill::before { content: "\f700"; } +.bi-arrow-through-heart::before { content: "\f701"; } +.bi-badge-sd-fill::before { content: "\f702"; } +.bi-badge-sd::before { content: "\f703"; } +.bi-bag-heart-fill::before { content: "\f704"; } +.bi-bag-heart::before { content: "\f705"; } +.bi-balloon-fill::before { content: "\f706"; } +.bi-balloon-heart-fill::before { content: "\f707"; } +.bi-balloon-heart::before { content: "\f708"; } +.bi-balloon::before { content: "\f709"; } +.bi-box2-fill::before { content: "\f70a"; } +.bi-box2-heart-fill::before { content: "\f70b"; } +.bi-box2-heart::before { content: "\f70c"; } +.bi-box2::before { content: "\f70d"; } +.bi-braces-asterisk::before { content: "\f70e"; } +.bi-calendar-heart-fill::before { content: "\f70f"; } +.bi-calendar-heart::before { content: "\f710"; } +.bi-calendar2-heart-fill::before { content: "\f711"; } +.bi-calendar2-heart::before { content: "\f712"; } +.bi-chat-heart-fill::before { content: "\f713"; } +.bi-chat-heart::before { content: "\f714"; } +.bi-chat-left-heart-fill::before { content: "\f715"; } +.bi-chat-left-heart::before { content: "\f716"; } +.bi-chat-right-heart-fill::before { content: "\f717"; } +.bi-chat-right-heart::before { content: "\f718"; } +.bi-chat-square-heart-fill::before { content: "\f719"; } +.bi-chat-square-heart::before { content: "\f71a"; } +.bi-clipboard-check-fill::before { content: "\f71b"; } +.bi-clipboard-data-fill::before { content: "\f71c"; } +.bi-clipboard-fill::before { content: "\f71d"; } +.bi-clipboard-heart-fill::before { content: "\f71e"; } +.bi-clipboard-heart::before { content: "\f71f"; } +.bi-clipboard-minus-fill::before { content: "\f720"; } +.bi-clipboard-plus-fill::before { content: "\f721"; } +.bi-clipboard-pulse::before { content: "\f722"; } +.bi-clipboard-x-fill::before { content: "\f723"; } +.bi-clipboard2-check-fill::before { content: "\f724"; } +.bi-clipboard2-check::before { content: "\f725"; } +.bi-clipboard2-data-fill::before { content: "\f726"; } +.bi-clipboard2-data::before { content: "\f727"; } +.bi-clipboard2-fill::before { content: "\f728"; } +.bi-clipboard2-heart-fill::before { content: "\f729"; } +.bi-clipboard2-heart::before { content: "\f72a"; } +.bi-clipboard2-minus-fill::before { content: "\f72b"; } +.bi-clipboard2-minus::before { content: "\f72c"; } +.bi-clipboard2-plus-fill::before { content: "\f72d"; } +.bi-clipboard2-plus::before { content: "\f72e"; } +.bi-clipboard2-pulse-fill::before { content: "\f72f"; } +.bi-clipboard2-pulse::before { content: "\f730"; } +.bi-clipboard2-x-fill::before { content: "\f731"; } +.bi-clipboard2-x::before { content: "\f732"; } +.bi-clipboard2::before { content: "\f733"; } +.bi-emoji-kiss-fill::before { content: "\f734"; } +.bi-emoji-kiss::before { content: "\f735"; } +.bi-envelope-heart-fill::before { content: "\f736"; } +.bi-envelope-heart::before { content: "\f737"; } +.bi-envelope-open-heart-fill::before { content: "\f738"; } +.bi-envelope-open-heart::before { content: "\f739"; } +.bi-envelope-paper-fill::before { content: "\f73a"; } +.bi-envelope-paper-heart-fill::before { content: "\f73b"; } +.bi-envelope-paper-heart::before { content: "\f73c"; } +.bi-envelope-paper::before { content: "\f73d"; } +.bi-filetype-aac::before { content: "\f73e"; } +.bi-filetype-ai::before { content: "\f73f"; } +.bi-filetype-bmp::before { content: "\f740"; } +.bi-filetype-cs::before { content: "\f741"; } +.bi-filetype-css::before { content: "\f742"; } +.bi-filetype-csv::before { content: "\f743"; } +.bi-filetype-doc::before { content: "\f744"; } +.bi-filetype-docx::before { content: "\f745"; } +.bi-filetype-exe::before { content: "\f746"; } +.bi-filetype-gif::before { content: "\f747"; } +.bi-filetype-heic::before { content: "\f748"; } +.bi-filetype-html::before { content: "\f749"; } +.bi-filetype-java::before { content: "\f74a"; } +.bi-filetype-jpg::before { content: "\f74b"; } +.bi-filetype-js::before { content: "\f74c"; } +.bi-filetype-jsx::before { content: "\f74d"; } +.bi-filetype-key::before { content: "\f74e"; } +.bi-filetype-m4p::before { content: "\f74f"; } +.bi-filetype-md::before { content: "\f750"; } +.bi-filetype-mdx::before { content: "\f751"; } +.bi-filetype-mov::before { content: "\f752"; } +.bi-filetype-mp3::before { content: "\f753"; } +.bi-filetype-mp4::before { content: "\f754"; } +.bi-filetype-otf::before { content: "\f755"; } +.bi-filetype-pdf::before { content: "\f756"; } +.bi-filetype-php::before { content: "\f757"; } +.bi-filetype-png::before { content: "\f758"; } +.bi-filetype-ppt-1::before { content: "\f759"; } +.bi-filetype-ppt::before { content: "\f75a"; } +.bi-filetype-psd::before { content: "\f75b"; } +.bi-filetype-py::before { content: "\f75c"; } +.bi-filetype-raw::before { content: "\f75d"; } +.bi-filetype-rb::before { content: "\f75e"; } +.bi-filetype-sass::before { content: "\f75f"; } +.bi-filetype-scss::before { content: "\f760"; } +.bi-filetype-sh::before { content: "\f761"; } +.bi-filetype-svg::before { content: "\f762"; } +.bi-filetype-tiff::before { content: "\f763"; } +.bi-filetype-tsx::before { content: "\f764"; } +.bi-filetype-ttf::before { content: "\f765"; } +.bi-filetype-txt::before { content: "\f766"; } +.bi-filetype-wav::before { content: "\f767"; } +.bi-filetype-woff::before { content: "\f768"; } +.bi-filetype-xls-1::before { content: "\f769"; } +.bi-filetype-xls::before { content: "\f76a"; } +.bi-filetype-xml::before { content: "\f76b"; } +.bi-filetype-yml::before { content: "\f76c"; } +.bi-heart-arrow::before { content: "\f76d"; } +.bi-heart-pulse-fill::before { content: "\f76e"; } +.bi-heart-pulse::before { content: "\f76f"; } +.bi-heartbreak-fill::before { content: "\f770"; } +.bi-heartbreak::before { content: "\f771"; } +.bi-hearts::before { content: "\f772"; } +.bi-hospital-fill::before { content: "\f773"; } +.bi-hospital::before { content: "\f774"; } +.bi-house-heart-fill::before { content: "\f775"; } +.bi-house-heart::before { content: "\f776"; } +.bi-incognito::before { content: "\f777"; } +.bi-magnet-fill::before { content: "\f778"; } +.bi-magnet::before { content: "\f779"; } +.bi-person-heart::before { content: "\f77a"; } +.bi-person-hearts::before { content: "\f77b"; } +.bi-phone-flip::before { content: "\f77c"; } +.bi-plugin::before { content: "\f77d"; } +.bi-postage-fill::before { content: "\f77e"; } +.bi-postage-heart-fill::before { content: "\f77f"; } +.bi-postage-heart::before { content: "\f780"; } +.bi-postage::before { content: "\f781"; } +.bi-postcard-fill::before { content: "\f782"; } +.bi-postcard-heart-fill::before { content: "\f783"; } +.bi-postcard-heart::before { content: "\f784"; } +.bi-postcard::before { content: "\f785"; } +.bi-search-heart-fill::before { content: "\f786"; } +.bi-search-heart::before { content: "\f787"; } +.bi-sliders2-vertical::before { content: "\f788"; } +.bi-sliders2::before { content: "\f789"; } +.bi-trash3-fill::before { content: "\f78a"; } +.bi-trash3::before { content: "\f78b"; } +.bi-valentine::before { content: "\f78c"; } +.bi-valentine2::before { content: "\f78d"; } +.bi-wrench-adjustable-circle-fill::before { content: "\f78e"; } +.bi-wrench-adjustable-circle::before { content: "\f78f"; } +.bi-wrench-adjustable::before { content: "\f790"; } +.bi-filetype-json::before { content: "\f791"; } +.bi-filetype-pptx::before { content: "\f792"; } +.bi-filetype-xlsx::before { content: "\f793"; } +.bi-1-circle-1::before { content: "\f794"; } +.bi-1-circle-fill-1::before { content: "\f795"; } +.bi-1-circle-fill::before { content: "\f796"; } +.bi-1-circle::before { content: "\f797"; } +.bi-1-square-fill::before { content: "\f798"; } +.bi-1-square::before { content: "\f799"; } +.bi-2-circle-1::before { content: "\f79a"; } +.bi-2-circle-fill-1::before { content: "\f79b"; } +.bi-2-circle-fill::before { content: "\f79c"; } +.bi-2-circle::before { content: "\f79d"; } +.bi-2-square-fill::before { content: "\f79e"; } +.bi-2-square::before { content: "\f79f"; } +.bi-3-circle-1::before { content: "\f7a0"; } +.bi-3-circle-fill-1::before { content: "\f7a1"; } +.bi-3-circle-fill::before { content: "\f7a2"; } +.bi-3-circle::before { content: "\f7a3"; } +.bi-3-square-fill::before { content: "\f7a4"; } +.bi-3-square::before { content: "\f7a5"; } +.bi-4-circle-1::before { content: "\f7a6"; } +.bi-4-circle-fill-1::before { content: "\f7a7"; } +.bi-4-circle-fill::before { content: "\f7a8"; } +.bi-4-circle::before { content: "\f7a9"; } +.bi-4-square-fill::before { content: "\f7aa"; } +.bi-4-square::before { content: "\f7ab"; } +.bi-5-circle-1::before { content: "\f7ac"; } +.bi-5-circle-fill-1::before { content: "\f7ad"; } +.bi-5-circle-fill::before { content: "\f7ae"; } +.bi-5-circle::before { content: "\f7af"; } +.bi-5-square-fill::before { content: "\f7b0"; } +.bi-5-square::before { content: "\f7b1"; } +.bi-6-circle-1::before { content: "\f7b2"; } +.bi-6-circle-fill-1::before { content: "\f7b3"; } +.bi-6-circle-fill::before { content: "\f7b4"; } +.bi-6-circle::before { content: "\f7b5"; } +.bi-6-square-fill::before { content: "\f7b6"; } +.bi-6-square::before { content: "\f7b7"; } +.bi-7-circle-1::before { content: "\f7b8"; } +.bi-7-circle-fill-1::before { content: "\f7b9"; } +.bi-7-circle-fill::before { content: "\f7ba"; } +.bi-7-circle::before { content: "\f7bb"; } +.bi-7-square-fill::before { content: "\f7bc"; } +.bi-7-square::before { content: "\f7bd"; } +.bi-8-circle-1::before { content: "\f7be"; } +.bi-8-circle-fill-1::before { content: "\f7bf"; } +.bi-8-circle-fill::before { content: "\f7c0"; } +.bi-8-circle::before { content: "\f7c1"; } +.bi-8-square-fill::before { content: "\f7c2"; } +.bi-8-square::before { content: "\f7c3"; } +.bi-9-circle-1::before { content: "\f7c4"; } +.bi-9-circle-fill-1::before { content: "\f7c5"; } +.bi-9-circle-fill::before { content: "\f7c6"; } +.bi-9-circle::before { content: "\f7c7"; } +.bi-9-square-fill::before { content: "\f7c8"; } +.bi-9-square::before { content: "\f7c9"; } +.bi-airplane-engines-fill::before { content: "\f7ca"; } +.bi-airplane-engines::before { content: "\f7cb"; } +.bi-airplane-fill::before { content: "\f7cc"; } +.bi-airplane::before { content: "\f7cd"; } +.bi-alexa::before { content: "\f7ce"; } +.bi-alipay::before { content: "\f7cf"; } +.bi-android::before { content: "\f7d0"; } +.bi-android2::before { content: "\f7d1"; } +.bi-box-fill::before { content: "\f7d2"; } +.bi-box-seam-fill::before { content: "\f7d3"; } +.bi-browser-chrome::before { content: "\f7d4"; } +.bi-browser-edge::before { content: "\f7d5"; } +.bi-browser-firefox::before { content: "\f7d6"; } +.bi-browser-safari::before { content: "\f7d7"; } +.bi-c-circle-1::before { content: "\f7d8"; } +.bi-c-circle-fill-1::before { content: "\f7d9"; } +.bi-c-circle-fill::before { content: "\f7da"; } +.bi-c-circle::before { content: "\f7db"; } +.bi-c-square-fill::before { content: "\f7dc"; } +.bi-c-square::before { content: "\f7dd"; } +.bi-capsule-pill::before { content: "\f7de"; } +.bi-capsule::before { content: "\f7df"; } +.bi-car-front-fill::before { content: "\f7e0"; } +.bi-car-front::before { content: "\f7e1"; } +.bi-cassette-fill::before { content: "\f7e2"; } +.bi-cassette::before { content: "\f7e3"; } +.bi-cc-circle-1::before { content: "\f7e4"; } +.bi-cc-circle-fill-1::before { content: "\f7e5"; } +.bi-cc-circle-fill::before { content: "\f7e6"; } +.bi-cc-circle::before { content: "\f7e7"; } +.bi-cc-square-fill::before { content: "\f7e8"; } +.bi-cc-square::before { content: "\f7e9"; } +.bi-cup-hot-fill::before { content: "\f7ea"; } +.bi-cup-hot::before { content: "\f7eb"; } +.bi-currency-rupee::before { content: "\f7ec"; } +.bi-dropbox::before { content: "\f7ed"; } +.bi-escape::before { content: "\f7ee"; } +.bi-fast-forward-btn-fill::before { content: "\f7ef"; } +.bi-fast-forward-btn::before { content: "\f7f0"; } +.bi-fast-forward-circle-fill::before { content: "\f7f1"; } +.bi-fast-forward-circle::before { content: "\f7f2"; } +.bi-fast-forward-fill::before { content: "\f7f3"; } +.bi-fast-forward::before { content: "\f7f4"; } +.bi-filetype-sql::before { content: "\f7f5"; } +.bi-fire::before { content: "\f7f6"; } +.bi-google-play::before { content: "\f7f7"; } +.bi-h-circle-1::before { content: "\f7f8"; } +.bi-h-circle-fill-1::before { content: "\f7f9"; } +.bi-h-circle-fill::before { content: "\f7fa"; } +.bi-h-circle::before { content: "\f7fb"; } +.bi-h-square-fill::before { content: "\f7fc"; } +.bi-h-square::before { content: "\f7fd"; } +.bi-indent::before { content: "\f7fe"; } +.bi-lungs-fill::before { content: "\f7ff"; } +.bi-lungs::before { content: "\f800"; } +.bi-microsoft-teams::before { content: "\f801"; } +.bi-p-circle-1::before { content: "\f802"; } +.bi-p-circle-fill-1::before { content: "\f803"; } +.bi-p-circle-fill::before { content: "\f804"; } +.bi-p-circle::before { content: "\f805"; } +.bi-p-square-fill::before { content: "\f806"; } +.bi-p-square::before { content: "\f807"; } +.bi-pass-fill::before { content: "\f808"; } +.bi-pass::before { content: "\f809"; } +.bi-prescription::before { content: "\f80a"; } +.bi-prescription2::before { content: "\f80b"; } +.bi-r-circle-1::before { content: "\f80c"; } +.bi-r-circle-fill-1::before { content: "\f80d"; } +.bi-r-circle-fill::before { content: "\f80e"; } +.bi-r-circle::before { content: "\f80f"; } +.bi-r-square-fill::before { content: "\f810"; } +.bi-r-square::before { content: "\f811"; } +.bi-repeat-1::before { content: "\f812"; } +.bi-repeat::before { content: "\f813"; } +.bi-rewind-btn-fill::before { content: "\f814"; } +.bi-rewind-btn::before { content: "\f815"; } +.bi-rewind-circle-fill::before { content: "\f816"; } +.bi-rewind-circle::before { content: "\f817"; } +.bi-rewind-fill::before { content: "\f818"; } +.bi-rewind::before { content: "\f819"; } +.bi-train-freight-front-fill::before { content: "\f81a"; } +.bi-train-freight-front::before { content: "\f81b"; } +.bi-train-front-fill::before { content: "\f81c"; } +.bi-train-front::before { content: "\f81d"; } +.bi-train-lightrail-front-fill::before { content: "\f81e"; } +.bi-train-lightrail-front::before { content: "\f81f"; } +.bi-truck-front-fill::before { content: "\f820"; } +.bi-truck-front::before { content: "\f821"; } +.bi-ubuntu::before { content: "\f822"; } +.bi-unindent::before { content: "\f823"; } +.bi-unity::before { content: "\f824"; } +.bi-universal-access-circle::before { content: "\f825"; } +.bi-universal-access::before { content: "\f826"; } +.bi-virus::before { content: "\f827"; } +.bi-virus2::before { content: "\f828"; } +.bi-wechat::before { content: "\f829"; } +.bi-yelp::before { content: "\f82a"; } +.bi-sign-stop-fill::before { content: "\f82b"; } +.bi-sign-stop-lights-fill::before { content: "\f82c"; } +.bi-sign-stop-lights::before { content: "\f82d"; } +.bi-sign-stop::before { content: "\f82e"; } +.bi-sign-turn-left-fill::before { content: "\f82f"; } +.bi-sign-turn-left::before { content: "\f830"; } +.bi-sign-turn-right-fill::before { content: "\f831"; } +.bi-sign-turn-right::before { content: "\f832"; } +.bi-sign-turn-slight-left-fill::before { content: "\f833"; } +.bi-sign-turn-slight-left::before { content: "\f834"; } +.bi-sign-turn-slight-right-fill::before { content: "\f835"; } +.bi-sign-turn-slight-right::before { content: "\f836"; } +.bi-sign-yield-fill::before { content: "\f837"; } +.bi-sign-yield::before { content: "\f838"; } +.bi-ev-station-fill::before { content: "\f839"; } +.bi-ev-station::before { content: "\f83a"; } +.bi-fuel-pump-diesel-fill::before { content: "\f83b"; } +.bi-fuel-pump-diesel::before { content: "\f83c"; } +.bi-fuel-pump-fill::before { content: "\f83d"; } +.bi-fuel-pump::before { content: "\f83e"; } +.bi-0-circle-fill::before { content: "\f83f"; } +.bi-0-circle::before { content: "\f840"; } +.bi-0-square-fill::before { content: "\f841"; } +.bi-0-square::before { content: "\f842"; } +.bi-rocket-fill::before { content: "\f843"; } +.bi-rocket-takeoff-fill::before { content: "\f844"; } +.bi-rocket-takeoff::before { content: "\f845"; } +.bi-rocket::before { content: "\f846"; } +.bi-stripe::before { content: "\f847"; } +.bi-subscript::before { content: "\f848"; } +.bi-superscript::before { content: "\f849"; } +.bi-trello::before { content: "\f84a"; } +.bi-envelope-at-fill::before { content: "\f84b"; } +.bi-envelope-at::before { content: "\f84c"; } +.bi-regex::before { content: "\f84d"; } +.bi-text-wrap::before { content: "\f84e"; } +.bi-sign-dead-end-fill::before { content: "\f84f"; } +.bi-sign-dead-end::before { content: "\f850"; } +.bi-sign-do-not-enter-fill::before { content: "\f851"; } +.bi-sign-do-not-enter::before { content: "\f852"; } +.bi-sign-intersection-fill::before { content: "\f853"; } +.bi-sign-intersection-side-fill::before { content: "\f854"; } +.bi-sign-intersection-side::before { content: "\f855"; } +.bi-sign-intersection-t-fill::before { content: "\f856"; } +.bi-sign-intersection-t::before { content: "\f857"; } +.bi-sign-intersection-y-fill::before { content: "\f858"; } +.bi-sign-intersection-y::before { content: "\f859"; } +.bi-sign-intersection::before { content: "\f85a"; } +.bi-sign-merge-left-fill::before { content: "\f85b"; } +.bi-sign-merge-left::before { content: "\f85c"; } +.bi-sign-merge-right-fill::before { content: "\f85d"; } +.bi-sign-merge-right::before { content: "\f85e"; } +.bi-sign-no-left-turn-fill::before { content: "\f85f"; } +.bi-sign-no-left-turn::before { content: "\f860"; } +.bi-sign-no-parking-fill::before { content: "\f861"; } +.bi-sign-no-parking::before { content: "\f862"; } +.bi-sign-no-right-turn-fill::before { content: "\f863"; } +.bi-sign-no-right-turn::before { content: "\f864"; } +.bi-sign-railroad-fill::before { content: "\f865"; } +.bi-sign-railroad::before { content: "\f866"; } +.bi-building-add::before { content: "\f867"; } +.bi-building-check::before { content: "\f868"; } +.bi-building-dash::before { content: "\f869"; } +.bi-building-down::before { content: "\f86a"; } +.bi-building-exclamation::before { content: "\f86b"; } +.bi-building-fill-add::before { content: "\f86c"; } +.bi-building-fill-check::before { content: "\f86d"; } +.bi-building-fill-dash::before { content: "\f86e"; } +.bi-building-fill-down::before { content: "\f86f"; } +.bi-building-fill-exclamation::before { content: "\f870"; } +.bi-building-fill-gear::before { content: "\f871"; } +.bi-building-fill-lock::before { content: "\f872"; } +.bi-building-fill-slash::before { content: "\f873"; } +.bi-building-fill-up::before { content: "\f874"; } +.bi-building-fill-x::before { content: "\f875"; } +.bi-building-fill::before { content: "\f876"; } +.bi-building-gear::before { content: "\f877"; } +.bi-building-lock::before { content: "\f878"; } +.bi-building-slash::before { content: "\f879"; } +.bi-building-up::before { content: "\f87a"; } +.bi-building-x::before { content: "\f87b"; } +.bi-buildings-fill::before { content: "\f87c"; } +.bi-buildings::before { content: "\f87d"; } +.bi-bus-front-fill::before { content: "\f87e"; } +.bi-bus-front::before { content: "\f87f"; } +.bi-ev-front-fill::before { content: "\f880"; } +.bi-ev-front::before { content: "\f881"; } +.bi-globe-americas::before { content: "\f882"; } +.bi-globe-asia-australia::before { content: "\f883"; } +.bi-globe-central-south-asia::before { content: "\f884"; } +.bi-globe-europe-africa::before { content: "\f885"; } +.bi-house-add-fill::before { content: "\f886"; } +.bi-house-add::before { content: "\f887"; } +.bi-house-check-fill::before { content: "\f888"; } +.bi-house-check::before { content: "\f889"; } +.bi-house-dash-fill::before { content: "\f88a"; } +.bi-house-dash::before { content: "\f88b"; } +.bi-house-down-fill::before { content: "\f88c"; } +.bi-house-down::before { content: "\f88d"; } +.bi-house-exclamation-fill::before { content: "\f88e"; } +.bi-house-exclamation::before { content: "\f88f"; } +.bi-house-gear-fill::before { content: "\f890"; } +.bi-house-gear::before { content: "\f891"; } +.bi-house-lock-fill::before { content: "\f892"; } +.bi-house-lock::before { content: "\f893"; } +.bi-house-slash-fill::before { content: "\f894"; } +.bi-house-slash::before { content: "\f895"; } +.bi-house-up-fill::before { content: "\f896"; } +.bi-house-up::before { content: "\f897"; } +.bi-house-x-fill::before { content: "\f898"; } +.bi-house-x::before { content: "\f899"; } +.bi-person-add::before { content: "\f89a"; } +.bi-person-down::before { content: "\f89b"; } +.bi-person-exclamation::before { content: "\f89c"; } +.bi-person-fill-add::before { content: "\f89d"; } +.bi-person-fill-check::before { content: "\f89e"; } +.bi-person-fill-dash::before { content: "\f89f"; } +.bi-person-fill-down::before { content: "\f8a0"; } +.bi-person-fill-exclamation::before { content: "\f8a1"; } +.bi-person-fill-gear::before { content: "\f8a2"; } +.bi-person-fill-lock::before { content: "\f8a3"; } +.bi-person-fill-slash::before { content: "\f8a4"; } +.bi-person-fill-up::before { content: "\f8a5"; } +.bi-person-fill-x::before { content: "\f8a6"; } +.bi-person-gear::before { content: "\f8a7"; } +.bi-person-lock::before { content: "\f8a8"; } +.bi-person-slash::before { content: "\f8a9"; } +.bi-person-up::before { content: "\f8aa"; } +.bi-scooter::before { content: "\f8ab"; } +.bi-taxi-front-fill::before { content: "\f8ac"; } +.bi-taxi-front::before { content: "\f8ad"; } +.bi-amd::before { content: "\f8ae"; } +.bi-database-add::before { content: "\f8af"; } +.bi-database-check::before { content: "\f8b0"; } +.bi-database-dash::before { content: "\f8b1"; } +.bi-database-down::before { content: "\f8b2"; } +.bi-database-exclamation::before { content: "\f8b3"; } +.bi-database-fill-add::before { content: "\f8b4"; } +.bi-database-fill-check::before { content: "\f8b5"; } +.bi-database-fill-dash::before { content: "\f8b6"; } +.bi-database-fill-down::before { content: "\f8b7"; } +.bi-database-fill-exclamation::before { content: "\f8b8"; } +.bi-database-fill-gear::before { content: "\f8b9"; } +.bi-database-fill-lock::before { content: "\f8ba"; } +.bi-database-fill-slash::before { content: "\f8bb"; } +.bi-database-fill-up::before { content: "\f8bc"; } +.bi-database-fill-x::before { content: "\f8bd"; } +.bi-database-fill::before { content: "\f8be"; } +.bi-database-gear::before { content: "\f8bf"; } +.bi-database-lock::before { content: "\f8c0"; } +.bi-database-slash::before { content: "\f8c1"; } +.bi-database-up::before { content: "\f8c2"; } +.bi-database-x::before { content: "\f8c3"; } +.bi-database::before { content: "\f8c4"; } +.bi-houses-fill::before { content: "\f8c5"; } +.bi-houses::before { content: "\f8c6"; } +.bi-nvidia::before { content: "\f8c7"; } +.bi-person-vcard-fill::before { content: "\f8c8"; } +.bi-person-vcard::before { content: "\f8c9"; } +.bi-sina-weibo::before { content: "\f8ca"; } +.bi-tencent-qq::before { content: "\f8cb"; } +.bi-wikipedia::before { content: "\f8cc"; } diff --git a/site_libs/bootstrap/bootstrap-icons.woff b/site_libs/bootstrap/bootstrap-icons.woff new file mode 100644 index 00000000..18d21d45 Binary files /dev/null and b/site_libs/bootstrap/bootstrap-icons.woff differ diff --git a/site_libs/bootstrap/bootstrap.min.css b/site_libs/bootstrap/bootstrap.min.css new file mode 100644 index 00000000..7a2c054c --- /dev/null +++ b/site_libs/bootstrap/bootstrap.min.css @@ -0,0 +1,10 @@ +ļ»æ/*! + * Bootstrap v5.1.3 (https://getbootstrap.com/) + * Copyright 2011-2021 The Bootstrap Authors + * Copyright 2011-2021 Twitter, Inc. + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */@import"https://fonts.googleapis.com/css2?family=Source+Sans+Pro:wght@300;400;700&display=swap";:root{--bs-blue: #2780e3;--bs-indigo: #6610f2;--bs-purple: #613d7c;--bs-pink: #e83e8c;--bs-red: #ff0039;--bs-orange: #f0ad4e;--bs-yellow: #ff7518;--bs-green: #3fb618;--bs-teal: #20c997;--bs-cyan: #9954bb;--bs-white: #fff;--bs-gray: #6c757d;--bs-gray-dark: #373a3c;--bs-gray-100: #f8f9fa;--bs-gray-200: #e9ecef;--bs-gray-300: #dee2e6;--bs-gray-400: #ced4da;--bs-gray-500: #adb5bd;--bs-gray-600: #6c757d;--bs-gray-700: #495057;--bs-gray-800: #373a3c;--bs-gray-900: #212529;--bs-default: #373a3c;--bs-primary: #2780e3;--bs-secondary: #373a3c;--bs-success: #3fb618;--bs-info: #9954bb;--bs-warning: #ff7518;--bs-danger: #ff0039;--bs-light: #f8f9fa;--bs-dark: #373a3c;--bs-default-rgb: 55, 58, 60;--bs-primary-rgb: 39, 128, 227;--bs-secondary-rgb: 55, 58, 60;--bs-success-rgb: 63, 182, 24;--bs-info-rgb: 153, 84, 187;--bs-warning-rgb: 255, 117, 24;--bs-danger-rgb: 255, 0, 57;--bs-light-rgb: 248, 249, 250;--bs-dark-rgb: 55, 58, 60;--bs-white-rgb: 255, 255, 255;--bs-black-rgb: 0, 0, 0;--bs-body-color-rgb: 55, 58, 60;--bs-body-bg-rgb: 255, 255, 255;--bs-font-sans-serif: "Source Sans Pro", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";--bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;--bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));--bs-root-font-size: 1em;--bs-body-font-family: var(--bs-font-sans-serif);--bs-body-font-size: 1rem;--bs-body-font-weight: 400;--bs-body-line-height: 1.7;--bs-body-color: #373a3c;--bs-body-bg: #fff}*,*::before,*::after{box-sizing:border-box}:root{font-size:var(--bs-root-font-size)}body{margin:0;font-family:var(--bs-body-font-family);font-size:var(--bs-body-font-size);font-weight:var(--bs-body-font-weight);line-height:var(--bs-body-line-height);color:var(--bs-body-color);text-align:var(--bs-body-text-align);background-color:var(--bs-body-bg);-webkit-text-size-adjust:100%;-webkit-tap-highlight-color:rgba(0,0,0,0)}hr{margin:1rem 0;color:inherit;background-color:currentColor;border:0;opacity:.25}hr:not([size]){height:1px}h6,.h6,h5,.h5,h4,.h4,h3,.h3,h2,.h2,h1,.h1{margin-top:0;margin-bottom:.5rem;font-weight:400;line-height:1.2}h1,.h1{font-size:calc(1.325rem + 0.9vw)}@media(min-width: 1200px){h1,.h1{font-size:2rem}}h2,.h2{font-size:calc(1.29rem + 0.48vw)}@media(min-width: 1200px){h2,.h2{font-size:1.65rem}}h3,.h3{font-size:calc(1.27rem + 0.24vw)}@media(min-width: 1200px){h3,.h3{font-size:1.45rem}}h4,.h4{font-size:1.25rem}h5,.h5{font-size:1.1rem}h6,.h6{font-size:1rem}p{margin-top:0;margin-bottom:1rem}abbr[title],abbr[data-bs-original-title]{text-decoration:underline dotted;-webkit-text-decoration:underline dotted;-moz-text-decoration:underline dotted;-ms-text-decoration:underline dotted;-o-text-decoration:underline dotted;cursor:help;text-decoration-skip-ink:none}address{margin-bottom:1rem;font-style:normal;line-height:inherit}ol,ul{padding-left:2rem}ol,ul,dl{margin-top:0;margin-bottom:1rem}ol ol,ul ul,ol ul,ul ol{margin-bottom:0}dt{font-weight:700}dd{margin-bottom:.5rem;margin-left:0}blockquote{margin:0 0 1rem;padding:.625rem 1.25rem;border-left:.25rem solid #e9ecef}blockquote p:last-child,blockquote ul:last-child,blockquote ol:last-child{margin-bottom:0}b,strong{font-weight:bolder}small,.small{font-size:0.875em}mark,.mark{padding:.2em;background-color:#fcf8e3}sub,sup{position:relative;font-size:0.75em;line-height:0;vertical-align:baseline}sub{bottom:-0.25em}sup{top:-0.5em}a{color:#2780e3;text-decoration:underline;-webkit-text-decoration:underline;-moz-text-decoration:underline;-ms-text-decoration:underline;-o-text-decoration:underline}a:hover{color:#1f66b6}a:not([href]):not([class]),a:not([href]):not([class]):hover{color:inherit;text-decoration:none}pre,code,kbd,samp{font-family:var(--bs-font-monospace);font-size:1em;direction:ltr /* rtl:ignore */;unicode-bidi:bidi-override}pre{display:block;margin-top:0;margin-bottom:1rem;overflow:auto;font-size:0.875em;color:#000;background-color:#f7f7f7;padding:.5rem;border:1px solid #dee2e6}pre code{background-color:rgba(0,0,0,0);font-size:inherit;color:inherit;word-break:normal}code{font-size:0.875em;color:#9753b8;background-color:#f7f7f7;padding:.125rem .25rem;word-wrap:break-word}a>code{color:inherit}kbd{padding:.4rem .4rem;font-size:0.875em;color:#fff;background-color:#212529}kbd kbd{padding:0;font-size:1em;font-weight:700}figure{margin:0 0 1rem}img,svg{vertical-align:middle}table{caption-side:bottom;border-collapse:collapse}caption{padding-top:.5rem;padding-bottom:.5rem;color:#6c757d;text-align:left}th{text-align:inherit;text-align:-webkit-match-parent}thead,tbody,tfoot,tr,td,th{border-color:inherit;border-style:solid;border-width:0}label{display:inline-block}button{border-radius:0}button:focus:not(:focus-visible){outline:0}input,button,select,optgroup,textarea{margin:0;font-family:inherit;font-size:inherit;line-height:inherit}button,select{text-transform:none}[role=button]{cursor:pointer}select{word-wrap:normal}select:disabled{opacity:1}[list]::-webkit-calendar-picker-indicator{display:none}button,[type=button],[type=reset],[type=submit]{-webkit-appearance:button}button:not(:disabled),[type=button]:not(:disabled),[type=reset]:not(:disabled),[type=submit]:not(:disabled){cursor:pointer}::-moz-focus-inner{padding:0;border-style:none}textarea{resize:vertical}fieldset{min-width:0;padding:0;margin:0;border:0}legend{float:left;width:100%;padding:0;margin-bottom:.5rem;font-size:calc(1.275rem + 0.3vw);line-height:inherit}@media(min-width: 1200px){legend{font-size:1.5rem}}legend+*{clear:left}::-webkit-datetime-edit-fields-wrapper,::-webkit-datetime-edit-text,::-webkit-datetime-edit-minute,::-webkit-datetime-edit-hour-field,::-webkit-datetime-edit-day-field,::-webkit-datetime-edit-month-field,::-webkit-datetime-edit-year-field{padding:0}::-webkit-inner-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:textfield}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-color-swatch-wrapper{padding:0}::file-selector-button{font:inherit}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}iframe{border:0}summary{display:list-item;cursor:pointer}progress{vertical-align:baseline}[hidden]{display:none !important}.lead{font-size:1.25rem;font-weight:300}.display-1{font-size:calc(1.625rem + 4.5vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-1{font-size:5rem}}.display-2{font-size:calc(1.575rem + 3.9vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-2{font-size:4.5rem}}.display-3{font-size:calc(1.525rem + 3.3vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-3{font-size:4rem}}.display-4{font-size:calc(1.475rem + 2.7vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-4{font-size:3.5rem}}.display-5{font-size:calc(1.425rem + 2.1vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-5{font-size:3rem}}.display-6{font-size:calc(1.375rem + 1.5vw);font-weight:300;line-height:1.2}@media(min-width: 1200px){.display-6{font-size:2.5rem}}.list-unstyled{padding-left:0;list-style:none}.list-inline{padding-left:0;list-style:none}.list-inline-item{display:inline-block}.list-inline-item:not(:last-child){margin-right:.5rem}.initialism{font-size:0.875em;text-transform:uppercase}.blockquote{margin-bottom:1rem;font-size:1.25rem}.blockquote>:last-child{margin-bottom:0}.blockquote-footer{margin-top:-1rem;margin-bottom:1rem;font-size:0.875em;color:#6c757d}.blockquote-footer::before{content:"ā "}.img-fluid{max-width:100%;height:auto}.img-thumbnail{padding:.25rem;background-color:#fff;border:1px solid #dee2e6;max-width:100%;height:auto}.figure{display:inline-block}.figure-img{margin-bottom:.5rem;line-height:1}.figure-caption{font-size:0.875em;color:#6c757d}.grid{display:grid;grid-template-rows:repeat(var(--bs-rows, 1), 1fr);grid-template-columns:repeat(var(--bs-columns, 12), 1fr);gap:var(--bs-gap, 1.5rem)}.grid .g-col-1{grid-column:auto/span 1}.grid .g-col-2{grid-column:auto/span 2}.grid .g-col-3{grid-column:auto/span 3}.grid .g-col-4{grid-column:auto/span 4}.grid .g-col-5{grid-column:auto/span 5}.grid .g-col-6{grid-column:auto/span 6}.grid .g-col-7{grid-column:auto/span 7}.grid .g-col-8{grid-column:auto/span 8}.grid .g-col-9{grid-column:auto/span 9}.grid .g-col-10{grid-column:auto/span 10}.grid .g-col-11{grid-column:auto/span 11}.grid .g-col-12{grid-column:auto/span 12}.grid .g-start-1{grid-column-start:1}.grid .g-start-2{grid-column-start:2}.grid .g-start-3{grid-column-start:3}.grid .g-start-4{grid-column-start:4}.grid .g-start-5{grid-column-start:5}.grid .g-start-6{grid-column-start:6}.grid .g-start-7{grid-column-start:7}.grid .g-start-8{grid-column-start:8}.grid .g-start-9{grid-column-start:9}.grid .g-start-10{grid-column-start:10}.grid .g-start-11{grid-column-start:11}@media(min-width: 576px){.grid .g-col-sm-1{grid-column:auto/span 1}.grid .g-col-sm-2{grid-column:auto/span 2}.grid .g-col-sm-3{grid-column:auto/span 3}.grid .g-col-sm-4{grid-column:auto/span 4}.grid .g-col-sm-5{grid-column:auto/span 5}.grid .g-col-sm-6{grid-column:auto/span 6}.grid .g-col-sm-7{grid-column:auto/span 7}.grid .g-col-sm-8{grid-column:auto/span 8}.grid .g-col-sm-9{grid-column:auto/span 9}.grid .g-col-sm-10{grid-column:auto/span 10}.grid .g-col-sm-11{grid-column:auto/span 11}.grid .g-col-sm-12{grid-column:auto/span 12}.grid .g-start-sm-1{grid-column-start:1}.grid .g-start-sm-2{grid-column-start:2}.grid .g-start-sm-3{grid-column-start:3}.grid .g-start-sm-4{grid-column-start:4}.grid .g-start-sm-5{grid-column-start:5}.grid .g-start-sm-6{grid-column-start:6}.grid .g-start-sm-7{grid-column-start:7}.grid .g-start-sm-8{grid-column-start:8}.grid .g-start-sm-9{grid-column-start:9}.grid .g-start-sm-10{grid-column-start:10}.grid .g-start-sm-11{grid-column-start:11}}@media(min-width: 768px){.grid .g-col-md-1{grid-column:auto/span 1}.grid .g-col-md-2{grid-column:auto/span 2}.grid .g-col-md-3{grid-column:auto/span 3}.grid .g-col-md-4{grid-column:auto/span 4}.grid .g-col-md-5{grid-column:auto/span 5}.grid .g-col-md-6{grid-column:auto/span 6}.grid .g-col-md-7{grid-column:auto/span 7}.grid .g-col-md-8{grid-column:auto/span 8}.grid .g-col-md-9{grid-column:auto/span 9}.grid .g-col-md-10{grid-column:auto/span 10}.grid .g-col-md-11{grid-column:auto/span 11}.grid .g-col-md-12{grid-column:auto/span 12}.grid .g-start-md-1{grid-column-start:1}.grid .g-start-md-2{grid-column-start:2}.grid .g-start-md-3{grid-column-start:3}.grid .g-start-md-4{grid-column-start:4}.grid .g-start-md-5{grid-column-start:5}.grid .g-start-md-6{grid-column-start:6}.grid .g-start-md-7{grid-column-start:7}.grid .g-start-md-8{grid-column-start:8}.grid .g-start-md-9{grid-column-start:9}.grid .g-start-md-10{grid-column-start:10}.grid .g-start-md-11{grid-column-start:11}}@media(min-width: 992px){.grid .g-col-lg-1{grid-column:auto/span 1}.grid .g-col-lg-2{grid-column:auto/span 2}.grid .g-col-lg-3{grid-column:auto/span 3}.grid .g-col-lg-4{grid-column:auto/span 4}.grid .g-col-lg-5{grid-column:auto/span 5}.grid .g-col-lg-6{grid-column:auto/span 6}.grid .g-col-lg-7{grid-column:auto/span 7}.grid .g-col-lg-8{grid-column:auto/span 8}.grid .g-col-lg-9{grid-column:auto/span 9}.grid .g-col-lg-10{grid-column:auto/span 10}.grid .g-col-lg-11{grid-column:auto/span 11}.grid .g-col-lg-12{grid-column:auto/span 12}.grid .g-start-lg-1{grid-column-start:1}.grid .g-start-lg-2{grid-column-start:2}.grid .g-start-lg-3{grid-column-start:3}.grid .g-start-lg-4{grid-column-start:4}.grid .g-start-lg-5{grid-column-start:5}.grid .g-start-lg-6{grid-column-start:6}.grid .g-start-lg-7{grid-column-start:7}.grid .g-start-lg-8{grid-column-start:8}.grid .g-start-lg-9{grid-column-start:9}.grid .g-start-lg-10{grid-column-start:10}.grid .g-start-lg-11{grid-column-start:11}}@media(min-width: 1200px){.grid .g-col-xl-1{grid-column:auto/span 1}.grid .g-col-xl-2{grid-column:auto/span 2}.grid .g-col-xl-3{grid-column:auto/span 3}.grid .g-col-xl-4{grid-column:auto/span 4}.grid .g-col-xl-5{grid-column:auto/span 5}.grid .g-col-xl-6{grid-column:auto/span 6}.grid .g-col-xl-7{grid-column:auto/span 7}.grid .g-col-xl-8{grid-column:auto/span 8}.grid .g-col-xl-9{grid-column:auto/span 9}.grid .g-col-xl-10{grid-column:auto/span 10}.grid .g-col-xl-11{grid-column:auto/span 11}.grid .g-col-xl-12{grid-column:auto/span 12}.grid .g-start-xl-1{grid-column-start:1}.grid .g-start-xl-2{grid-column-start:2}.grid .g-start-xl-3{grid-column-start:3}.grid .g-start-xl-4{grid-column-start:4}.grid .g-start-xl-5{grid-column-start:5}.grid .g-start-xl-6{grid-column-start:6}.grid .g-start-xl-7{grid-column-start:7}.grid .g-start-xl-8{grid-column-start:8}.grid .g-start-xl-9{grid-column-start:9}.grid .g-start-xl-10{grid-column-start:10}.grid .g-start-xl-11{grid-column-start:11}}@media(min-width: 1400px){.grid .g-col-xxl-1{grid-column:auto/span 1}.grid .g-col-xxl-2{grid-column:auto/span 2}.grid .g-col-xxl-3{grid-column:auto/span 3}.grid .g-col-xxl-4{grid-column:auto/span 4}.grid .g-col-xxl-5{grid-column:auto/span 5}.grid .g-col-xxl-6{grid-column:auto/span 6}.grid .g-col-xxl-7{grid-column:auto/span 7}.grid .g-col-xxl-8{grid-column:auto/span 8}.grid .g-col-xxl-9{grid-column:auto/span 9}.grid .g-col-xxl-10{grid-column:auto/span 10}.grid .g-col-xxl-11{grid-column:auto/span 11}.grid .g-col-xxl-12{grid-column:auto/span 12}.grid .g-start-xxl-1{grid-column-start:1}.grid .g-start-xxl-2{grid-column-start:2}.grid .g-start-xxl-3{grid-column-start:3}.grid .g-start-xxl-4{grid-column-start:4}.grid .g-start-xxl-5{grid-column-start:5}.grid .g-start-xxl-6{grid-column-start:6}.grid .g-start-xxl-7{grid-column-start:7}.grid .g-start-xxl-8{grid-column-start:8}.grid .g-start-xxl-9{grid-column-start:9}.grid .g-start-xxl-10{grid-column-start:10}.grid .g-start-xxl-11{grid-column-start:11}}.table{--bs-table-bg: transparent;--bs-table-accent-bg: transparent;--bs-table-striped-color: #373a3c;--bs-table-striped-bg: rgba(0, 0, 0, 0.05);--bs-table-active-color: #373a3c;--bs-table-active-bg: rgba(0, 0, 0, 0.1);--bs-table-hover-color: #373a3c;--bs-table-hover-bg: rgba(0, 0, 0, 0.075);width:100%;margin-bottom:1rem;color:#373a3c;vertical-align:top;border-color:#dee2e6}.table>:not(caption)>*>*{padding:.5rem .5rem;background-color:var(--bs-table-bg);border-bottom-width:1px;box-shadow:inset 0 0 0 9999px var(--bs-table-accent-bg)}.table>tbody{vertical-align:inherit}.table>thead{vertical-align:bottom}.table>:not(:first-child){border-top:2px solid #b6babc}.caption-top{caption-side:top}.table-sm>:not(caption)>*>*{padding:.25rem .25rem}.table-bordered>:not(caption)>*{border-width:1px 0}.table-bordered>:not(caption)>*>*{border-width:0 1px}.table-borderless>:not(caption)>*>*{border-bottom-width:0}.table-borderless>:not(:first-child){border-top-width:0}.table-striped>tbody>tr:nth-of-type(odd)>*{--bs-table-accent-bg: var(--bs-table-striped-bg);color:var(--bs-table-striped-color)}.table-active{--bs-table-accent-bg: var(--bs-table-active-bg);color:var(--bs-table-active-color)}.table-hover>tbody>tr:hover>*{--bs-table-accent-bg: var(--bs-table-hover-bg);color:var(--bs-table-hover-color)}.table-primary{--bs-table-bg: #d4e6f9;--bs-table-striped-bg: #c9dbed;--bs-table-striped-color: #000;--bs-table-active-bg: #bfcfe0;--bs-table-active-color: #000;--bs-table-hover-bg: #c4d5e6;--bs-table-hover-color: #000;color:#000;border-color:#bfcfe0}.table-secondary{--bs-table-bg: #d7d8d8;--bs-table-striped-bg: #cccdcd;--bs-table-striped-color: #000;--bs-table-active-bg: #c2c2c2;--bs-table-active-color: #000;--bs-table-hover-bg: #c7c8c8;--bs-table-hover-color: #000;color:#000;border-color:#c2c2c2}.table-success{--bs-table-bg: #d9f0d1;--bs-table-striped-bg: #cee4c7;--bs-table-striped-color: #000;--bs-table-active-bg: #c3d8bc;--bs-table-active-color: #000;--bs-table-hover-bg: #c9dec1;--bs-table-hover-color: #000;color:#000;border-color:#c3d8bc}.table-info{--bs-table-bg: #ebddf1;--bs-table-striped-bg: #dfd2e5;--bs-table-striped-color: #000;--bs-table-active-bg: #d4c7d9;--bs-table-active-color: #000;--bs-table-hover-bg: #d9ccdf;--bs-table-hover-color: #000;color:#000;border-color:#d4c7d9}.table-warning{--bs-table-bg: #ffe3d1;--bs-table-striped-bg: #f2d8c7;--bs-table-striped-color: #000;--bs-table-active-bg: #e6ccbc;--bs-table-active-color: #000;--bs-table-hover-bg: #ecd2c1;--bs-table-hover-color: #000;color:#000;border-color:#e6ccbc}.table-danger{--bs-table-bg: #ffccd7;--bs-table-striped-bg: #f2c2cc;--bs-table-striped-color: #000;--bs-table-active-bg: #e6b8c2;--bs-table-active-color: #000;--bs-table-hover-bg: #ecbdc7;--bs-table-hover-color: #000;color:#000;border-color:#e6b8c2}.table-light{--bs-table-bg: #f8f9fa;--bs-table-striped-bg: #ecedee;--bs-table-striped-color: #000;--bs-table-active-bg: #dfe0e1;--bs-table-active-color: #000;--bs-table-hover-bg: #e5e6e7;--bs-table-hover-color: #000;color:#000;border-color:#dfe0e1}.table-dark{--bs-table-bg: #373a3c;--bs-table-striped-bg: #414446;--bs-table-striped-color: #fff;--bs-table-active-bg: #4b4e50;--bs-table-active-color: #fff;--bs-table-hover-bg: #46494b;--bs-table-hover-color: #fff;color:#fff;border-color:#4b4e50}.table-responsive{overflow-x:auto;-webkit-overflow-scrolling:touch}@media(max-width: 575.98px){.table-responsive-sm{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width: 767.98px){.table-responsive-md{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width: 991.98px){.table-responsive-lg{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width: 1199.98px){.table-responsive-xl{overflow-x:auto;-webkit-overflow-scrolling:touch}}@media(max-width: 1399.98px){.table-responsive-xxl{overflow-x:auto;-webkit-overflow-scrolling:touch}}.form-label,.shiny-input-container .control-label{margin-bottom:.5rem}.col-form-label{padding-top:calc(0.375rem + 1px);padding-bottom:calc(0.375rem + 1px);margin-bottom:0;font-size:inherit;line-height:1.5}.col-form-label-lg{padding-top:calc(0.5rem + 1px);padding-bottom:calc(0.5rem + 1px);font-size:1.25rem}.col-form-label-sm{padding-top:calc(0.25rem + 1px);padding-bottom:calc(0.25rem + 1px);font-size:0.875rem}.form-text{margin-top:.25rem;font-size:0.875em;color:#6c757d}.form-control{display:block;width:100%;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#373a3c;background-color:#fff;background-clip:padding-box;border:1px solid #ced4da;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;border-radius:0;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-control{transition:none}}.form-control[type=file]{overflow:hidden}.form-control[type=file]:not(:disabled):not([readonly]){cursor:pointer}.form-control:focus{color:#373a3c;background-color:#fff;border-color:#93c0f1;outline:0;box-shadow:0 0 0 .25rem rgba(39,128,227,.25)}.form-control::-webkit-date-and-time-value{height:1.5em}.form-control::placeholder{color:#6c757d;opacity:1}.form-control:disabled,.form-control[readonly]{background-color:#e9ecef;opacity:1}.form-control::file-selector-button{padding:.375rem .75rem;margin:-0.375rem -0.75rem;margin-inline-end:.75rem;color:#373a3c;background-color:#e9ecef;pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:1px;border-radius:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-control::file-selector-button{transition:none}}.form-control:hover:not(:disabled):not([readonly])::file-selector-button{background-color:#dde0e3}.form-control::-webkit-file-upload-button{padding:.375rem .75rem;margin:-0.375rem -0.75rem;margin-inline-end:.75rem;color:#373a3c;background-color:#e9ecef;pointer-events:none;border-color:inherit;border-style:solid;border-width:0;border-inline-end-width:1px;border-radius:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-control::-webkit-file-upload-button{transition:none}}.form-control:hover:not(:disabled):not([readonly])::-webkit-file-upload-button{background-color:#dde0e3}.form-control-plaintext{display:block;width:100%;padding:.375rem 0;margin-bottom:0;line-height:1.5;color:#373a3c;background-color:rgba(0,0,0,0);border:solid rgba(0,0,0,0);border-width:1px 0}.form-control-plaintext.form-control-sm,.form-control-plaintext.form-control-lg{padding-right:0;padding-left:0}.form-control-sm{min-height:calc(1.5em + 0.5rem + 2px);padding:.25rem .5rem;font-size:0.875rem}.form-control-sm::file-selector-button{padding:.25rem .5rem;margin:-0.25rem -0.5rem;margin-inline-end:.5rem}.form-control-sm::-webkit-file-upload-button{padding:.25rem .5rem;margin:-0.25rem -0.5rem;margin-inline-end:.5rem}.form-control-lg{min-height:calc(1.5em + 1rem + 2px);padding:.5rem 1rem;font-size:1.25rem}.form-control-lg::file-selector-button{padding:.5rem 1rem;margin:-0.5rem -1rem;margin-inline-end:1rem}.form-control-lg::-webkit-file-upload-button{padding:.5rem 1rem;margin:-0.5rem -1rem;margin-inline-end:1rem}textarea.form-control{min-height:calc(1.5em + 0.75rem + 2px)}textarea.form-control-sm{min-height:calc(1.5em + 0.5rem + 2px)}textarea.form-control-lg{min-height:calc(1.5em + 1rem + 2px)}.form-control-color{width:3rem;height:auto;padding:.375rem}.form-control-color:not(:disabled):not([readonly]){cursor:pointer}.form-control-color::-moz-color-swatch{height:1.5em}.form-control-color::-webkit-color-swatch{height:1.5em}.form-select{display:block;width:100%;padding:.375rem 2.25rem .375rem .75rem;-moz-padding-start:calc(0.75rem - 3px);font-size:1rem;font-weight:400;line-height:1.5;color:#373a3c;background-color:#fff;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23373a3c' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right .75rem center;background-size:16px 12px;border:1px solid #ced4da;border-radius:0;transition:border-color .15s ease-in-out,box-shadow .15s ease-in-out;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none}@media(prefers-reduced-motion: reduce){.form-select{transition:none}}.form-select:focus{border-color:#93c0f1;outline:0;box-shadow:0 0 0 .25rem rgba(39,128,227,.25)}.form-select[multiple],.form-select[size]:not([size="1"]){padding-right:.75rem;background-image:none}.form-select:disabled{background-color:#e9ecef}.form-select:-moz-focusring{color:rgba(0,0,0,0);text-shadow:0 0 0 #373a3c}.form-select-sm{padding-top:.25rem;padding-bottom:.25rem;padding-left:.5rem;font-size:0.875rem}.form-select-lg{padding-top:.5rem;padding-bottom:.5rem;padding-left:1rem;font-size:1.25rem}.form-check,.shiny-input-container .checkbox,.shiny-input-container .radio{display:block;min-height:1.5rem;padding-left:0;margin-bottom:.125rem}.form-check .form-check-input,.form-check .shiny-input-container .checkbox input,.form-check .shiny-input-container .radio input,.shiny-input-container .checkbox .form-check-input,.shiny-input-container .checkbox .shiny-input-container .checkbox input,.shiny-input-container .checkbox .shiny-input-container .radio input,.shiny-input-container .radio .form-check-input,.shiny-input-container .radio .shiny-input-container .checkbox input,.shiny-input-container .radio .shiny-input-container .radio input{float:left;margin-left:0}.form-check-input,.shiny-input-container .checkbox input,.shiny-input-container .checkbox-inline input,.shiny-input-container .radio input,.shiny-input-container .radio-inline input{width:1em;height:1em;margin-top:.35em;vertical-align:top;background-color:#fff;background-repeat:no-repeat;background-position:center;background-size:contain;border:1px solid rgba(0,0,0,.25);appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none;color-adjust:exact;-webkit-print-color-adjust:exact}.form-check-input[type=radio],.shiny-input-container .checkbox input[type=radio],.shiny-input-container .checkbox-inline input[type=radio],.shiny-input-container .radio input[type=radio],.shiny-input-container .radio-inline input[type=radio]{border-radius:50%}.form-check-input:active,.shiny-input-container .checkbox input:active,.shiny-input-container .checkbox-inline input:active,.shiny-input-container .radio input:active,.shiny-input-container .radio-inline input:active{filter:brightness(90%)}.form-check-input:focus,.shiny-input-container .checkbox input:focus,.shiny-input-container .checkbox-inline input:focus,.shiny-input-container .radio input:focus,.shiny-input-container .radio-inline input:focus{border-color:#93c0f1;outline:0;box-shadow:0 0 0 .25rem rgba(39,128,227,.25)}.form-check-input:checked,.shiny-input-container .checkbox input:checked,.shiny-input-container .checkbox-inline input:checked,.shiny-input-container .radio input:checked,.shiny-input-container .radio-inline input:checked{background-color:#2780e3;border-color:#2780e3}.form-check-input:checked[type=checkbox],.shiny-input-container .checkbox input:checked[type=checkbox],.shiny-input-container .checkbox-inline input:checked[type=checkbox],.shiny-input-container .radio input:checked[type=checkbox],.shiny-input-container .radio-inline input:checked[type=checkbox]{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10l3 3l6-6'/%3e%3c/svg%3e")}.form-check-input:checked[type=radio],.shiny-input-container .checkbox input:checked[type=radio],.shiny-input-container .checkbox-inline input:checked[type=radio],.shiny-input-container .radio input:checked[type=radio],.shiny-input-container .radio-inline input:checked[type=radio]{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='2' fill='%23fff'/%3e%3c/svg%3e")}.form-check-input[type=checkbox]:indeterminate,.shiny-input-container .checkbox input[type=checkbox]:indeterminate,.shiny-input-container .checkbox-inline input[type=checkbox]:indeterminate,.shiny-input-container .radio input[type=checkbox]:indeterminate,.shiny-input-container .radio-inline input[type=checkbox]:indeterminate{background-color:#2780e3;border-color:#2780e3;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 20 20'%3e%3cpath fill='none' stroke='%23fff' stroke-linecap='round' stroke-linejoin='round' stroke-width='3' d='M6 10h8'/%3e%3c/svg%3e")}.form-check-input:disabled,.shiny-input-container .checkbox input:disabled,.shiny-input-container .checkbox-inline input:disabled,.shiny-input-container .radio input:disabled,.shiny-input-container .radio-inline input:disabled{pointer-events:none;filter:none;opacity:.5}.form-check-input[disabled]~.form-check-label,.form-check-input[disabled]~span,.form-check-input:disabled~.form-check-label,.form-check-input:disabled~span,.shiny-input-container .checkbox input[disabled]~.form-check-label,.shiny-input-container .checkbox input[disabled]~span,.shiny-input-container .checkbox input:disabled~.form-check-label,.shiny-input-container .checkbox input:disabled~span,.shiny-input-container .checkbox-inline input[disabled]~.form-check-label,.shiny-input-container .checkbox-inline input[disabled]~span,.shiny-input-container .checkbox-inline input:disabled~.form-check-label,.shiny-input-container .checkbox-inline input:disabled~span,.shiny-input-container .radio input[disabled]~.form-check-label,.shiny-input-container .radio input[disabled]~span,.shiny-input-container .radio input:disabled~.form-check-label,.shiny-input-container .radio input:disabled~span,.shiny-input-container .radio-inline input[disabled]~.form-check-label,.shiny-input-container .radio-inline input[disabled]~span,.shiny-input-container .radio-inline input:disabled~.form-check-label,.shiny-input-container .radio-inline input:disabled~span{opacity:.5}.form-check-label,.shiny-input-container .checkbox label,.shiny-input-container .checkbox-inline label,.shiny-input-container .radio label,.shiny-input-container .radio-inline label{cursor:pointer}.form-switch{padding-left:2.5em}.form-switch .form-check-input{width:2em;margin-left:-2.5em;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='rgba%280, 0, 0, 0.25%29'/%3e%3c/svg%3e");background-position:left center;transition:background-position .15s ease-in-out}@media(prefers-reduced-motion: reduce){.form-switch .form-check-input{transition:none}}.form-switch .form-check-input:focus{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%2393c0f1'/%3e%3c/svg%3e")}.form-switch .form-check-input:checked{background-position:right center;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='-4 -4 8 8'%3e%3ccircle r='3' fill='%23fff'/%3e%3c/svg%3e")}.form-check-inline,.shiny-input-container .checkbox-inline,.shiny-input-container .radio-inline{display:inline-block;margin-right:1rem}.btn-check{position:absolute;clip:rect(0, 0, 0, 0);pointer-events:none}.btn-check[disabled]+.btn,.btn-check:disabled+.btn{pointer-events:none;filter:none;opacity:.65}.form-range{width:100%;height:1.5rem;padding:0;background-color:rgba(0,0,0,0);appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none}.form-range:focus{outline:0}.form-range:focus::-webkit-slider-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(39,128,227,.25)}.form-range:focus::-moz-range-thumb{box-shadow:0 0 0 1px #fff,0 0 0 .25rem rgba(39,128,227,.25)}.form-range::-moz-focus-outer{border:0}.form-range::-webkit-slider-thumb{width:1rem;height:1rem;margin-top:-0.25rem;background-color:#2780e3;border:0;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none}@media(prefers-reduced-motion: reduce){.form-range::-webkit-slider-thumb{transition:none}}.form-range::-webkit-slider-thumb:active{background-color:#bed9f7}.form-range::-webkit-slider-runnable-track{width:100%;height:.5rem;color:rgba(0,0,0,0);cursor:pointer;background-color:#dee2e6;border-color:rgba(0,0,0,0)}.form-range::-moz-range-thumb{width:1rem;height:1rem;background-color:#2780e3;border:0;transition:background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out;appearance:none;-webkit-appearance:none;-moz-appearance:none;-ms-appearance:none;-o-appearance:none}@media(prefers-reduced-motion: reduce){.form-range::-moz-range-thumb{transition:none}}.form-range::-moz-range-thumb:active{background-color:#bed9f7}.form-range::-moz-range-track{width:100%;height:.5rem;color:rgba(0,0,0,0);cursor:pointer;background-color:#dee2e6;border-color:rgba(0,0,0,0)}.form-range:disabled{pointer-events:none}.form-range:disabled::-webkit-slider-thumb{background-color:#adb5bd}.form-range:disabled::-moz-range-thumb{background-color:#adb5bd}.form-floating{position:relative}.form-floating>.form-control,.form-floating>.form-select{height:calc(3.5rem + 2px);line-height:1.25}.form-floating>label{position:absolute;top:0;left:0;height:100%;padding:1rem .75rem;pointer-events:none;border:1px solid rgba(0,0,0,0);transform-origin:0 0;transition:opacity .1s ease-in-out,transform .1s ease-in-out}@media(prefers-reduced-motion: reduce){.form-floating>label{transition:none}}.form-floating>.form-control{padding:1rem .75rem}.form-floating>.form-control::placeholder{color:rgba(0,0,0,0)}.form-floating>.form-control:focus,.form-floating>.form-control:not(:placeholder-shown){padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:-webkit-autofill{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-select{padding-top:1.625rem;padding-bottom:.625rem}.form-floating>.form-control:focus~label,.form-floating>.form-control:not(:placeholder-shown)~label,.form-floating>.form-select~label{opacity:.65;transform:scale(0.85) translateY(-0.5rem) translateX(0.15rem)}.form-floating>.form-control:-webkit-autofill~label{opacity:.65;transform:scale(0.85) translateY(-0.5rem) translateX(0.15rem)}.input-group{position:relative;display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;align-items:stretch;-webkit-align-items:stretch;width:100%}.input-group>.form-control,.input-group>.form-select{position:relative;flex:1 1 auto;-webkit-flex:1 1 auto;width:1%;min-width:0}.input-group>.form-control:focus,.input-group>.form-select:focus{z-index:3}.input-group .btn{position:relative;z-index:2}.input-group .btn:focus{z-index:3}.input-group-text{display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;padding:.375rem .75rem;font-size:1rem;font-weight:400;line-height:1.5;color:#373a3c;text-align:center;white-space:nowrap;background-color:#e9ecef;border:1px solid #ced4da}.input-group-lg>.form-control,.input-group-lg>.form-select,.input-group-lg>.input-group-text,.input-group-lg>.btn{padding:.5rem 1rem;font-size:1.25rem}.input-group-sm>.form-control,.input-group-sm>.form-select,.input-group-sm>.input-group-text,.input-group-sm>.btn{padding:.25rem .5rem;font-size:0.875rem}.input-group-lg>.form-select,.input-group-sm>.form-select{padding-right:3rem}.input-group>:not(:first-child):not(.dropdown-menu):not(.valid-tooltip):not(.valid-feedback):not(.invalid-tooltip):not(.invalid-feedback){margin-left:-1px}.valid-feedback{display:none;width:100%;margin-top:.25rem;font-size:0.875em;color:#3fb618}.valid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:0.875rem;color:#fff;background-color:rgba(63,182,24,.9)}.was-validated :valid~.valid-feedback,.was-validated :valid~.valid-tooltip,.is-valid~.valid-feedback,.is-valid~.valid-tooltip{display:block}.was-validated .form-control:valid,.form-control.is-valid{border-color:#3fb618;padding-right:calc(1.5em + 0.75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%233fb618' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(0.375em + 0.1875rem) center;background-size:calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-control:valid:focus,.form-control.is-valid:focus{border-color:#3fb618;box-shadow:0 0 0 .25rem rgba(63,182,24,.25)}.was-validated textarea.form-control:valid,textarea.form-control.is-valid{padding-right:calc(1.5em + 0.75rem);background-position:top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem)}.was-validated .form-select:valid,.form-select.is-valid{border-color:#3fb618}.was-validated .form-select:valid:not([multiple]):not([size]),.was-validated .form-select:valid:not([multiple])[size="1"],.form-select.is-valid:not([multiple]):not([size]),.form-select.is-valid:not([multiple])[size="1"]{padding-right:4.125rem;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23373a3c' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e"),url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'%3e%3cpath fill='%233fb618' d='M2.3 6.73L.6 4.53c-.4-1.04.46-1.4 1.1-.8l1.1 1.4 3.4-3.8c.6-.63 1.6-.27 1.2.7l-4 4.6c-.43.5-.8.4-1.1.1z'/%3e%3c/svg%3e");background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-select:valid:focus,.form-select.is-valid:focus{border-color:#3fb618;box-shadow:0 0 0 .25rem rgba(63,182,24,.25)}.was-validated .form-check-input:valid,.form-check-input.is-valid{border-color:#3fb618}.was-validated .form-check-input:valid:checked,.form-check-input.is-valid:checked{background-color:#3fb618}.was-validated .form-check-input:valid:focus,.form-check-input.is-valid:focus{box-shadow:0 0 0 .25rem rgba(63,182,24,.25)}.was-validated .form-check-input:valid~.form-check-label,.form-check-input.is-valid~.form-check-label{color:#3fb618}.form-check-inline .form-check-input~.valid-feedback{margin-left:.5em}.was-validated .input-group .form-control:valid,.input-group .form-control.is-valid,.was-validated .input-group .form-select:valid,.input-group .form-select.is-valid{z-index:1}.was-validated .input-group .form-control:valid:focus,.input-group .form-control.is-valid:focus,.was-validated .input-group .form-select:valid:focus,.input-group .form-select.is-valid:focus{z-index:3}.invalid-feedback{display:none;width:100%;margin-top:.25rem;font-size:0.875em;color:#ff0039}.invalid-tooltip{position:absolute;top:100%;z-index:5;display:none;max-width:100%;padding:.25rem .5rem;margin-top:.1rem;font-size:0.875rem;color:#fff;background-color:rgba(255,0,57,.9)}.was-validated :invalid~.invalid-feedback,.was-validated :invalid~.invalid-tooltip,.is-invalid~.invalid-feedback,.is-invalid~.invalid-tooltip{display:block}.was-validated .form-control:invalid,.form-control.is-invalid{border-color:#ff0039;padding-right:calc(1.5em + 0.75rem);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23ff0039'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23ff0039' stroke='none'/%3e%3c/svg%3e");background-repeat:no-repeat;background-position:right calc(0.375em + 0.1875rem) center;background-size:calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-control:invalid:focus,.form-control.is-invalid:focus{border-color:#ff0039;box-shadow:0 0 0 .25rem rgba(255,0,57,.25)}.was-validated textarea.form-control:invalid,textarea.form-control.is-invalid{padding-right:calc(1.5em + 0.75rem);background-position:top calc(0.375em + 0.1875rem) right calc(0.375em + 0.1875rem)}.was-validated .form-select:invalid,.form-select.is-invalid{border-color:#ff0039}.was-validated .form-select:invalid:not([multiple]):not([size]),.was-validated .form-select:invalid:not([multiple])[size="1"],.form-select.is-invalid:not([multiple]):not([size]),.form-select.is-invalid:not([multiple])[size="1"]{padding-right:4.125rem;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%23373a3c' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='M2 5l6 6 6-6'/%3e%3c/svg%3e"),url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12' width='12' height='12' fill='none' stroke='%23ff0039'%3e%3ccircle cx='6' cy='6' r='4.5'/%3e%3cpath stroke-linejoin='round' d='M5.8 3.6h.4L6 6.5z'/%3e%3ccircle cx='6' cy='8.2' r='.6' fill='%23ff0039' stroke='none'/%3e%3c/svg%3e");background-position:right .75rem center,center right 2.25rem;background-size:16px 12px,calc(0.75em + 0.375rem) calc(0.75em + 0.375rem)}.was-validated .form-select:invalid:focus,.form-select.is-invalid:focus{border-color:#ff0039;box-shadow:0 0 0 .25rem rgba(255,0,57,.25)}.was-validated .form-check-input:invalid,.form-check-input.is-invalid{border-color:#ff0039}.was-validated .form-check-input:invalid:checked,.form-check-input.is-invalid:checked{background-color:#ff0039}.was-validated .form-check-input:invalid:focus,.form-check-input.is-invalid:focus{box-shadow:0 0 0 .25rem rgba(255,0,57,.25)}.was-validated .form-check-input:invalid~.form-check-label,.form-check-input.is-invalid~.form-check-label{color:#ff0039}.form-check-inline .form-check-input~.invalid-feedback{margin-left:.5em}.was-validated .input-group .form-control:invalid,.input-group .form-control.is-invalid,.was-validated .input-group .form-select:invalid,.input-group .form-select.is-invalid{z-index:2}.was-validated .input-group .form-control:invalid:focus,.input-group .form-control.is-invalid:focus,.was-validated .input-group .form-select:invalid:focus,.input-group .form-select.is-invalid:focus{z-index:3}.btn{display:inline-block;font-weight:400;line-height:1.5;color:#373a3c;text-align:center;text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;vertical-align:middle;cursor:pointer;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;background-color:rgba(0,0,0,0);border:1px solid rgba(0,0,0,0);padding:.375rem .75rem;font-size:1rem;border-radius:0;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.btn{transition:none}}.btn:hover{color:#373a3c}.btn-check:focus+.btn,.btn:focus{outline:0;box-shadow:0 0 0 .25rem rgba(39,128,227,.25)}.btn:disabled,.btn.disabled,fieldset:disabled .btn{pointer-events:none;opacity:.65}.btn-default{color:#fff;background-color:#373a3c;border-color:#373a3c}.btn-default:hover{color:#fff;background-color:#2f3133;border-color:#2c2e30}.btn-check:focus+.btn-default,.btn-default:focus{color:#fff;background-color:#2f3133;border-color:#2c2e30;box-shadow:0 0 0 .25rem rgba(85,88,89,.5)}.btn-check:checked+.btn-default,.btn-check:active+.btn-default,.btn-default:active,.btn-default.active,.show>.btn-default.dropdown-toggle{color:#fff;background-color:#2c2e30;border-color:#292c2d}.btn-check:checked+.btn-default:focus,.btn-check:active+.btn-default:focus,.btn-default:active:focus,.btn-default.active:focus,.show>.btn-default.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(85,88,89,.5)}.btn-default:disabled,.btn-default.disabled{color:#fff;background-color:#373a3c;border-color:#373a3c}.btn-primary{color:#fff;background-color:#2780e3;border-color:#2780e3}.btn-primary:hover{color:#fff;background-color:#216dc1;border-color:#1f66b6}.btn-check:focus+.btn-primary,.btn-primary:focus{color:#fff;background-color:#216dc1;border-color:#1f66b6;box-shadow:0 0 0 .25rem rgba(71,147,231,.5)}.btn-check:checked+.btn-primary,.btn-check:active+.btn-primary,.btn-primary:active,.btn-primary.active,.show>.btn-primary.dropdown-toggle{color:#fff;background-color:#1f66b6;border-color:#1d60aa}.btn-check:checked+.btn-primary:focus,.btn-check:active+.btn-primary:focus,.btn-primary:active:focus,.btn-primary.active:focus,.show>.btn-primary.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(71,147,231,.5)}.btn-primary:disabled,.btn-primary.disabled{color:#fff;background-color:#2780e3;border-color:#2780e3}.btn-secondary{color:#fff;background-color:#373a3c;border-color:#373a3c}.btn-secondary:hover{color:#fff;background-color:#2f3133;border-color:#2c2e30}.btn-check:focus+.btn-secondary,.btn-secondary:focus{color:#fff;background-color:#2f3133;border-color:#2c2e30;box-shadow:0 0 0 .25rem rgba(85,88,89,.5)}.btn-check:checked+.btn-secondary,.btn-check:active+.btn-secondary,.btn-secondary:active,.btn-secondary.active,.show>.btn-secondary.dropdown-toggle{color:#fff;background-color:#2c2e30;border-color:#292c2d}.btn-check:checked+.btn-secondary:focus,.btn-check:active+.btn-secondary:focus,.btn-secondary:active:focus,.btn-secondary.active:focus,.show>.btn-secondary.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(85,88,89,.5)}.btn-secondary:disabled,.btn-secondary.disabled{color:#fff;background-color:#373a3c;border-color:#373a3c}.btn-success{color:#fff;background-color:#3fb618;border-color:#3fb618}.btn-success:hover{color:#fff;background-color:#369b14;border-color:#329213}.btn-check:focus+.btn-success,.btn-success:focus{color:#fff;background-color:#369b14;border-color:#329213;box-shadow:0 0 0 .25rem rgba(92,193,59,.5)}.btn-check:checked+.btn-success,.btn-check:active+.btn-success,.btn-success:active,.btn-success.active,.show>.btn-success.dropdown-toggle{color:#fff;background-color:#329213;border-color:#2f8912}.btn-check:checked+.btn-success:focus,.btn-check:active+.btn-success:focus,.btn-success:active:focus,.btn-success.active:focus,.show>.btn-success.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(92,193,59,.5)}.btn-success:disabled,.btn-success.disabled{color:#fff;background-color:#3fb618;border-color:#3fb618}.btn-info{color:#fff;background-color:#9954bb;border-color:#9954bb}.btn-info:hover{color:#fff;background-color:#82479f;border-color:#7a4396}.btn-check:focus+.btn-info,.btn-info:focus{color:#fff;background-color:#82479f;border-color:#7a4396;box-shadow:0 0 0 .25rem rgba(168,110,197,.5)}.btn-check:checked+.btn-info,.btn-check:active+.btn-info,.btn-info:active,.btn-info.active,.show>.btn-info.dropdown-toggle{color:#fff;background-color:#7a4396;border-color:#733f8c}.btn-check:checked+.btn-info:focus,.btn-check:active+.btn-info:focus,.btn-info:active:focus,.btn-info.active:focus,.show>.btn-info.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(168,110,197,.5)}.btn-info:disabled,.btn-info.disabled{color:#fff;background-color:#9954bb;border-color:#9954bb}.btn-warning{color:#fff;background-color:#ff7518;border-color:#ff7518}.btn-warning:hover{color:#fff;background-color:#d96314;border-color:#cc5e13}.btn-check:focus+.btn-warning,.btn-warning:focus{color:#fff;background-color:#d96314;border-color:#cc5e13;box-shadow:0 0 0 .25rem rgba(255,138,59,.5)}.btn-check:checked+.btn-warning,.btn-check:active+.btn-warning,.btn-warning:active,.btn-warning.active,.show>.btn-warning.dropdown-toggle{color:#fff;background-color:#cc5e13;border-color:#bf5812}.btn-check:checked+.btn-warning:focus,.btn-check:active+.btn-warning:focus,.btn-warning:active:focus,.btn-warning.active:focus,.show>.btn-warning.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(255,138,59,.5)}.btn-warning:disabled,.btn-warning.disabled{color:#fff;background-color:#ff7518;border-color:#ff7518}.btn-danger{color:#fff;background-color:#ff0039;border-color:#ff0039}.btn-danger:hover{color:#fff;background-color:#d90030;border-color:#cc002e}.btn-check:focus+.btn-danger,.btn-danger:focus{color:#fff;background-color:#d90030;border-color:#cc002e;box-shadow:0 0 0 .25rem rgba(255,38,87,.5)}.btn-check:checked+.btn-danger,.btn-check:active+.btn-danger,.btn-danger:active,.btn-danger.active,.show>.btn-danger.dropdown-toggle{color:#fff;background-color:#cc002e;border-color:#bf002b}.btn-check:checked+.btn-danger:focus,.btn-check:active+.btn-danger:focus,.btn-danger:active:focus,.btn-danger.active:focus,.show>.btn-danger.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(255,38,87,.5)}.btn-danger:disabled,.btn-danger.disabled{color:#fff;background-color:#ff0039;border-color:#ff0039}.btn-light{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-light:hover{color:#000;background-color:#f9fafb;border-color:#f9fafb}.btn-check:focus+.btn-light,.btn-light:focus{color:#000;background-color:#f9fafb;border-color:#f9fafb;box-shadow:0 0 0 .25rem rgba(211,212,213,.5)}.btn-check:checked+.btn-light,.btn-check:active+.btn-light,.btn-light:active,.btn-light.active,.show>.btn-light.dropdown-toggle{color:#000;background-color:#f9fafb;border-color:#f9fafb}.btn-check:checked+.btn-light:focus,.btn-check:active+.btn-light:focus,.btn-light:active:focus,.btn-light.active:focus,.show>.btn-light.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(211,212,213,.5)}.btn-light:disabled,.btn-light.disabled{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-dark{color:#fff;background-color:#373a3c;border-color:#373a3c}.btn-dark:hover{color:#fff;background-color:#2f3133;border-color:#2c2e30}.btn-check:focus+.btn-dark,.btn-dark:focus{color:#fff;background-color:#2f3133;border-color:#2c2e30;box-shadow:0 0 0 .25rem rgba(85,88,89,.5)}.btn-check:checked+.btn-dark,.btn-check:active+.btn-dark,.btn-dark:active,.btn-dark.active,.show>.btn-dark.dropdown-toggle{color:#fff;background-color:#2c2e30;border-color:#292c2d}.btn-check:checked+.btn-dark:focus,.btn-check:active+.btn-dark:focus,.btn-dark:active:focus,.btn-dark.active:focus,.show>.btn-dark.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(85,88,89,.5)}.btn-dark:disabled,.btn-dark.disabled{color:#fff;background-color:#373a3c;border-color:#373a3c}.btn-outline-default{color:#373a3c;border-color:#373a3c;background-color:rgba(0,0,0,0)}.btn-outline-default:hover{color:#fff;background-color:#373a3c;border-color:#373a3c}.btn-check:focus+.btn-outline-default,.btn-outline-default:focus{box-shadow:0 0 0 .25rem rgba(55,58,60,.5)}.btn-check:checked+.btn-outline-default,.btn-check:active+.btn-outline-default,.btn-outline-default:active,.btn-outline-default.active,.btn-outline-default.dropdown-toggle.show{color:#fff;background-color:#373a3c;border-color:#373a3c}.btn-check:checked+.btn-outline-default:focus,.btn-check:active+.btn-outline-default:focus,.btn-outline-default:active:focus,.btn-outline-default.active:focus,.btn-outline-default.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(55,58,60,.5)}.btn-outline-default:disabled,.btn-outline-default.disabled{color:#373a3c;background-color:rgba(0,0,0,0)}.btn-outline-primary{color:#2780e3;border-color:#2780e3;background-color:rgba(0,0,0,0)}.btn-outline-primary:hover{color:#fff;background-color:#2780e3;border-color:#2780e3}.btn-check:focus+.btn-outline-primary,.btn-outline-primary:focus{box-shadow:0 0 0 .25rem rgba(39,128,227,.5)}.btn-check:checked+.btn-outline-primary,.btn-check:active+.btn-outline-primary,.btn-outline-primary:active,.btn-outline-primary.active,.btn-outline-primary.dropdown-toggle.show{color:#fff;background-color:#2780e3;border-color:#2780e3}.btn-check:checked+.btn-outline-primary:focus,.btn-check:active+.btn-outline-primary:focus,.btn-outline-primary:active:focus,.btn-outline-primary.active:focus,.btn-outline-primary.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(39,128,227,.5)}.btn-outline-primary:disabled,.btn-outline-primary.disabled{color:#2780e3;background-color:rgba(0,0,0,0)}.btn-outline-secondary{color:#373a3c;border-color:#373a3c;background-color:rgba(0,0,0,0)}.btn-outline-secondary:hover{color:#fff;background-color:#373a3c;border-color:#373a3c}.btn-check:focus+.btn-outline-secondary,.btn-outline-secondary:focus{box-shadow:0 0 0 .25rem rgba(55,58,60,.5)}.btn-check:checked+.btn-outline-secondary,.btn-check:active+.btn-outline-secondary,.btn-outline-secondary:active,.btn-outline-secondary.active,.btn-outline-secondary.dropdown-toggle.show{color:#fff;background-color:#373a3c;border-color:#373a3c}.btn-check:checked+.btn-outline-secondary:focus,.btn-check:active+.btn-outline-secondary:focus,.btn-outline-secondary:active:focus,.btn-outline-secondary.active:focus,.btn-outline-secondary.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(55,58,60,.5)}.btn-outline-secondary:disabled,.btn-outline-secondary.disabled{color:#373a3c;background-color:rgba(0,0,0,0)}.btn-outline-success{color:#3fb618;border-color:#3fb618;background-color:rgba(0,0,0,0)}.btn-outline-success:hover{color:#fff;background-color:#3fb618;border-color:#3fb618}.btn-check:focus+.btn-outline-success,.btn-outline-success:focus{box-shadow:0 0 0 .25rem rgba(63,182,24,.5)}.btn-check:checked+.btn-outline-success,.btn-check:active+.btn-outline-success,.btn-outline-success:active,.btn-outline-success.active,.btn-outline-success.dropdown-toggle.show{color:#fff;background-color:#3fb618;border-color:#3fb618}.btn-check:checked+.btn-outline-success:focus,.btn-check:active+.btn-outline-success:focus,.btn-outline-success:active:focus,.btn-outline-success.active:focus,.btn-outline-success.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(63,182,24,.5)}.btn-outline-success:disabled,.btn-outline-success.disabled{color:#3fb618;background-color:rgba(0,0,0,0)}.btn-outline-info{color:#9954bb;border-color:#9954bb;background-color:rgba(0,0,0,0)}.btn-outline-info:hover{color:#fff;background-color:#9954bb;border-color:#9954bb}.btn-check:focus+.btn-outline-info,.btn-outline-info:focus{box-shadow:0 0 0 .25rem rgba(153,84,187,.5)}.btn-check:checked+.btn-outline-info,.btn-check:active+.btn-outline-info,.btn-outline-info:active,.btn-outline-info.active,.btn-outline-info.dropdown-toggle.show{color:#fff;background-color:#9954bb;border-color:#9954bb}.btn-check:checked+.btn-outline-info:focus,.btn-check:active+.btn-outline-info:focus,.btn-outline-info:active:focus,.btn-outline-info.active:focus,.btn-outline-info.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(153,84,187,.5)}.btn-outline-info:disabled,.btn-outline-info.disabled{color:#9954bb;background-color:rgba(0,0,0,0)}.btn-outline-warning{color:#ff7518;border-color:#ff7518;background-color:rgba(0,0,0,0)}.btn-outline-warning:hover{color:#fff;background-color:#ff7518;border-color:#ff7518}.btn-check:focus+.btn-outline-warning,.btn-outline-warning:focus{box-shadow:0 0 0 .25rem rgba(255,117,24,.5)}.btn-check:checked+.btn-outline-warning,.btn-check:active+.btn-outline-warning,.btn-outline-warning:active,.btn-outline-warning.active,.btn-outline-warning.dropdown-toggle.show{color:#fff;background-color:#ff7518;border-color:#ff7518}.btn-check:checked+.btn-outline-warning:focus,.btn-check:active+.btn-outline-warning:focus,.btn-outline-warning:active:focus,.btn-outline-warning.active:focus,.btn-outline-warning.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(255,117,24,.5)}.btn-outline-warning:disabled,.btn-outline-warning.disabled{color:#ff7518;background-color:rgba(0,0,0,0)}.btn-outline-danger{color:#ff0039;border-color:#ff0039;background-color:rgba(0,0,0,0)}.btn-outline-danger:hover{color:#fff;background-color:#ff0039;border-color:#ff0039}.btn-check:focus+.btn-outline-danger,.btn-outline-danger:focus{box-shadow:0 0 0 .25rem rgba(255,0,57,.5)}.btn-check:checked+.btn-outline-danger,.btn-check:active+.btn-outline-danger,.btn-outline-danger:active,.btn-outline-danger.active,.btn-outline-danger.dropdown-toggle.show{color:#fff;background-color:#ff0039;border-color:#ff0039}.btn-check:checked+.btn-outline-danger:focus,.btn-check:active+.btn-outline-danger:focus,.btn-outline-danger:active:focus,.btn-outline-danger.active:focus,.btn-outline-danger.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(255,0,57,.5)}.btn-outline-danger:disabled,.btn-outline-danger.disabled{color:#ff0039;background-color:rgba(0,0,0,0)}.btn-outline-light{color:#f8f9fa;border-color:#f8f9fa;background-color:rgba(0,0,0,0)}.btn-outline-light:hover{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-check:focus+.btn-outline-light,.btn-outline-light:focus{box-shadow:0 0 0 .25rem rgba(248,249,250,.5)}.btn-check:checked+.btn-outline-light,.btn-check:active+.btn-outline-light,.btn-outline-light:active,.btn-outline-light.active,.btn-outline-light.dropdown-toggle.show{color:#000;background-color:#f8f9fa;border-color:#f8f9fa}.btn-check:checked+.btn-outline-light:focus,.btn-check:active+.btn-outline-light:focus,.btn-outline-light:active:focus,.btn-outline-light.active:focus,.btn-outline-light.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(248,249,250,.5)}.btn-outline-light:disabled,.btn-outline-light.disabled{color:#f8f9fa;background-color:rgba(0,0,0,0)}.btn-outline-dark{color:#373a3c;border-color:#373a3c;background-color:rgba(0,0,0,0)}.btn-outline-dark:hover{color:#fff;background-color:#373a3c;border-color:#373a3c}.btn-check:focus+.btn-outline-dark,.btn-outline-dark:focus{box-shadow:0 0 0 .25rem rgba(55,58,60,.5)}.btn-check:checked+.btn-outline-dark,.btn-check:active+.btn-outline-dark,.btn-outline-dark:active,.btn-outline-dark.active,.btn-outline-dark.dropdown-toggle.show{color:#fff;background-color:#373a3c;border-color:#373a3c}.btn-check:checked+.btn-outline-dark:focus,.btn-check:active+.btn-outline-dark:focus,.btn-outline-dark:active:focus,.btn-outline-dark.active:focus,.btn-outline-dark.dropdown-toggle.show:focus{box-shadow:0 0 0 .25rem rgba(55,58,60,.5)}.btn-outline-dark:disabled,.btn-outline-dark.disabled{color:#373a3c;background-color:rgba(0,0,0,0)}.btn-link{font-weight:400;color:#2780e3;text-decoration:underline;-webkit-text-decoration:underline;-moz-text-decoration:underline;-ms-text-decoration:underline;-o-text-decoration:underline}.btn-link:hover{color:#1f66b6}.btn-link:disabled,.btn-link.disabled{color:#6c757d}.btn-lg,.btn-group-lg>.btn{padding:.5rem 1rem;font-size:1.25rem;border-radius:0}.btn-sm,.btn-group-sm>.btn{padding:.25rem .5rem;font-size:0.875rem;border-radius:0}.fade{transition:opacity .15s linear}@media(prefers-reduced-motion: reduce){.fade{transition:none}}.fade:not(.show){opacity:0}.collapse:not(.show){display:none}.collapsing{height:0;overflow:hidden;transition:height .2s ease}@media(prefers-reduced-motion: reduce){.collapsing{transition:none}}.collapsing.collapse-horizontal{width:0;height:auto;transition:width .35s ease}@media(prefers-reduced-motion: reduce){.collapsing.collapse-horizontal{transition:none}}.dropup,.dropend,.dropdown,.dropstart{position:relative}.dropdown-toggle{white-space:nowrap}.dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid;border-right:.3em solid rgba(0,0,0,0);border-bottom:0;border-left:.3em solid rgba(0,0,0,0)}.dropdown-toggle:empty::after{margin-left:0}.dropdown-menu{position:absolute;z-index:1000;display:none;min-width:10rem;padding:.5rem 0;margin:0;font-size:1rem;color:#373a3c;text-align:left;list-style:none;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.15)}.dropdown-menu[data-bs-popper]{top:100%;left:0;margin-top:.125rem}.dropdown-menu-start{--bs-position: start}.dropdown-menu-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-end{--bs-position: end}.dropdown-menu-end[data-bs-popper]{right:0;left:auto}@media(min-width: 576px){.dropdown-menu-sm-start{--bs-position: start}.dropdown-menu-sm-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-sm-end{--bs-position: end}.dropdown-menu-sm-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 768px){.dropdown-menu-md-start{--bs-position: start}.dropdown-menu-md-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-md-end{--bs-position: end}.dropdown-menu-md-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 992px){.dropdown-menu-lg-start{--bs-position: start}.dropdown-menu-lg-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-lg-end{--bs-position: end}.dropdown-menu-lg-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 1200px){.dropdown-menu-xl-start{--bs-position: start}.dropdown-menu-xl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xl-end{--bs-position: end}.dropdown-menu-xl-end[data-bs-popper]{right:0;left:auto}}@media(min-width: 1400px){.dropdown-menu-xxl-start{--bs-position: start}.dropdown-menu-xxl-start[data-bs-popper]{right:auto;left:0}.dropdown-menu-xxl-end{--bs-position: end}.dropdown-menu-xxl-end[data-bs-popper]{right:0;left:auto}}.dropup .dropdown-menu[data-bs-popper]{top:auto;bottom:100%;margin-top:0;margin-bottom:.125rem}.dropup .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:0;border-right:.3em solid rgba(0,0,0,0);border-bottom:.3em solid;border-left:.3em solid rgba(0,0,0,0)}.dropup .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-menu[data-bs-popper]{top:0;right:auto;left:100%;margin-top:0;margin-left:.125rem}.dropend .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:"";border-top:.3em solid rgba(0,0,0,0);border-right:0;border-bottom:.3em solid rgba(0,0,0,0);border-left:.3em solid}.dropend .dropdown-toggle:empty::after{margin-left:0}.dropend .dropdown-toggle::after{vertical-align:0}.dropstart .dropdown-menu[data-bs-popper]{top:0;right:100%;left:auto;margin-top:0;margin-right:.125rem}.dropstart .dropdown-toggle::after{display:inline-block;margin-left:.255em;vertical-align:.255em;content:""}.dropstart .dropdown-toggle::after{display:none}.dropstart .dropdown-toggle::before{display:inline-block;margin-right:.255em;vertical-align:.255em;content:"";border-top:.3em solid rgba(0,0,0,0);border-right:.3em solid;border-bottom:.3em solid rgba(0,0,0,0)}.dropstart .dropdown-toggle:empty::after{margin-left:0}.dropstart .dropdown-toggle::before{vertical-align:0}.dropdown-divider{height:0;margin:.5rem 0;overflow:hidden;border-top:1px solid rgba(0,0,0,.15)}.dropdown-item{display:block;width:100%;padding:.25rem 1rem;clear:both;font-weight:400;color:#212529;text-align:inherit;text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;white-space:nowrap;background-color:rgba(0,0,0,0);border:0}.dropdown-item:hover,.dropdown-item:focus{color:#1e2125;background-color:#e9ecef}.dropdown-item.active,.dropdown-item:active{color:#fff;text-decoration:none;background-color:#2780e3}.dropdown-item.disabled,.dropdown-item:disabled{color:#adb5bd;pointer-events:none;background-color:rgba(0,0,0,0)}.dropdown-menu.show{display:block}.dropdown-header{display:block;padding:.5rem 1rem;margin-bottom:0;font-size:0.875rem;color:#6c757d;white-space:nowrap}.dropdown-item-text{display:block;padding:.25rem 1rem;color:#212529}.dropdown-menu-dark{color:#dee2e6;background-color:#373a3c;border-color:rgba(0,0,0,.15)}.dropdown-menu-dark .dropdown-item{color:#dee2e6}.dropdown-menu-dark .dropdown-item:hover,.dropdown-menu-dark .dropdown-item:focus{color:#fff;background-color:rgba(255,255,255,.15)}.dropdown-menu-dark .dropdown-item.active,.dropdown-menu-dark .dropdown-item:active{color:#fff;background-color:#2780e3}.dropdown-menu-dark .dropdown-item.disabled,.dropdown-menu-dark .dropdown-item:disabled{color:#adb5bd}.dropdown-menu-dark .dropdown-divider{border-color:rgba(0,0,0,.15)}.dropdown-menu-dark .dropdown-item-text{color:#dee2e6}.dropdown-menu-dark .dropdown-header{color:#adb5bd}.btn-group,.btn-group-vertical{position:relative;display:inline-flex;vertical-align:middle}.btn-group>.btn,.btn-group-vertical>.btn{position:relative;flex:1 1 auto;-webkit-flex:1 1 auto}.btn-group>.btn-check:checked+.btn,.btn-group>.btn-check:focus+.btn,.btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active,.btn-group-vertical>.btn-check:checked+.btn,.btn-group-vertical>.btn-check:focus+.btn,.btn-group-vertical>.btn:hover,.btn-group-vertical>.btn:focus,.btn-group-vertical>.btn:active,.btn-group-vertical>.btn.active{z-index:1}.btn-toolbar{display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;justify-content:flex-start;-webkit-justify-content:flex-start}.btn-toolbar .input-group{width:auto}.btn-group>.btn:not(:first-child),.btn-group>.btn-group:not(:first-child){margin-left:-1px}.dropdown-toggle-split{padding-right:.5625rem;padding-left:.5625rem}.dropdown-toggle-split::after,.dropup .dropdown-toggle-split::after,.dropend .dropdown-toggle-split::after{margin-left:0}.dropstart .dropdown-toggle-split::before{margin-right:0}.btn-sm+.dropdown-toggle-split,.btn-group-sm>.btn+.dropdown-toggle-split{padding-right:.375rem;padding-left:.375rem}.btn-lg+.dropdown-toggle-split,.btn-group-lg>.btn+.dropdown-toggle-split{padding-right:.75rem;padding-left:.75rem}.btn-group-vertical{flex-direction:column;-webkit-flex-direction:column;align-items:flex-start;-webkit-align-items:flex-start;justify-content:center;-webkit-justify-content:center}.btn-group-vertical>.btn,.btn-group-vertical>.btn-group{width:100%}.btn-group-vertical>.btn:not(:first-child),.btn-group-vertical>.btn-group:not(:first-child){margin-top:-1px}.nav{display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;padding-left:0;margin-bottom:0;list-style:none}.nav-link{display:block;padding:.5rem 1rem;color:#2780e3;text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out}@media(prefers-reduced-motion: reduce){.nav-link{transition:none}}.nav-link:hover,.nav-link:focus{color:#1f66b6}.nav-link.disabled{color:#6c757d;pointer-events:none;cursor:default}.nav-tabs{border-bottom:1px solid #dee2e6}.nav-tabs .nav-link{margin-bottom:-1px;background:none;border:1px solid rgba(0,0,0,0)}.nav-tabs .nav-link:hover,.nav-tabs .nav-link:focus{border-color:#e9ecef #e9ecef #dee2e6;isolation:isolate}.nav-tabs .nav-link.disabled{color:#6c757d;background-color:rgba(0,0,0,0);border-color:rgba(0,0,0,0)}.nav-tabs .nav-link.active,.nav-tabs .nav-item.show .nav-link{color:#495057;background-color:#fff;border-color:#dee2e6 #dee2e6 #fff}.nav-tabs .dropdown-menu{margin-top:-1px}.nav-pills .nav-link{background:none;border:0}.nav-pills .nav-link.active,.nav-pills .show>.nav-link{color:#fff;background-color:#2780e3}.nav-fill>.nav-link,.nav-fill .nav-item{flex:1 1 auto;-webkit-flex:1 1 auto;text-align:center}.nav-justified>.nav-link,.nav-justified .nav-item{flex-basis:0;-webkit-flex-basis:0;flex-grow:1;-webkit-flex-grow:1;text-align:center}.nav-fill .nav-item .nav-link,.nav-justified .nav-item .nav-link{width:100%}.tab-content>.tab-pane{display:none}.tab-content>.active{display:block}.navbar{position:relative;display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;align-items:center;-webkit-align-items:center;justify-content:space-between;-webkit-justify-content:space-between;padding-top:.5rem;padding-bottom:.5rem}.navbar>.container-xxl,.navbar>.container-xl,.navbar>.container-lg,.navbar>.container-md,.navbar>.container-sm,.navbar>.container,.navbar>.container-fluid{display:flex;display:-webkit-flex;flex-wrap:inherit;-webkit-flex-wrap:inherit;align-items:center;-webkit-align-items:center;justify-content:space-between;-webkit-justify-content:space-between}.navbar-brand{padding-top:.3125rem;padding-bottom:.3125rem;margin-right:1rem;font-size:1.25rem;text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;white-space:nowrap}.navbar-nav{display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;padding-left:0;margin-bottom:0;list-style:none}.navbar-nav .nav-link{padding-right:0;padding-left:0}.navbar-nav .dropdown-menu{position:static}.navbar-text{padding-top:.5rem;padding-bottom:.5rem}.navbar-collapse{flex-basis:100%;-webkit-flex-basis:100%;flex-grow:1;-webkit-flex-grow:1;align-items:center;-webkit-align-items:center}.navbar-toggler{padding:.25 0;font-size:1.25rem;line-height:1;background-color:rgba(0,0,0,0);border:1px solid rgba(0,0,0,0);transition:box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.navbar-toggler{transition:none}}.navbar-toggler:hover{text-decoration:none}.navbar-toggler:focus{text-decoration:none;outline:0;box-shadow:0 0 0 .25rem}.navbar-toggler-icon{display:inline-block;width:1.5em;height:1.5em;vertical-align:middle;background-repeat:no-repeat;background-position:center;background-size:100%}.navbar-nav-scroll{max-height:var(--bs-scroll-height, 75vh);overflow-y:auto}@media(min-width: 576px){.navbar-expand-sm{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-sm .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-sm .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-sm .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-sm .navbar-nav-scroll{overflow:visible}.navbar-expand-sm .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-sm .navbar-toggler{display:none}.navbar-expand-sm .offcanvas-header{display:none}.navbar-expand-sm .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;-webkit-flex-grow:1;visibility:visible !important;background-color:rgba(0,0,0,0);border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-sm .offcanvas-top,.navbar-expand-sm .offcanvas-bottom{height:auto;border-top:0;border-bottom:0}.navbar-expand-sm .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 768px){.navbar-expand-md{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-md .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-md .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-md .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-md .navbar-nav-scroll{overflow:visible}.navbar-expand-md .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-md .navbar-toggler{display:none}.navbar-expand-md .offcanvas-header{display:none}.navbar-expand-md .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;-webkit-flex-grow:1;visibility:visible !important;background-color:rgba(0,0,0,0);border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-md .offcanvas-top,.navbar-expand-md .offcanvas-bottom{height:auto;border-top:0;border-bottom:0}.navbar-expand-md .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 992px){.navbar-expand-lg{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-lg .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-lg .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-lg .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-lg .navbar-nav-scroll{overflow:visible}.navbar-expand-lg .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-lg .navbar-toggler{display:none}.navbar-expand-lg .offcanvas-header{display:none}.navbar-expand-lg .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;-webkit-flex-grow:1;visibility:visible !important;background-color:rgba(0,0,0,0);border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-lg .offcanvas-top,.navbar-expand-lg .offcanvas-bottom{height:auto;border-top:0;border-bottom:0}.navbar-expand-lg .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 1200px){.navbar-expand-xl{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-xl .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-xl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xl .navbar-nav-scroll{overflow:visible}.navbar-expand-xl .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-xl .navbar-toggler{display:none}.navbar-expand-xl .offcanvas-header{display:none}.navbar-expand-xl .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;-webkit-flex-grow:1;visibility:visible !important;background-color:rgba(0,0,0,0);border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-xl .offcanvas-top,.navbar-expand-xl .offcanvas-bottom{height:auto;border-top:0;border-bottom:0}.navbar-expand-xl .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}@media(min-width: 1400px){.navbar-expand-xxl{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand-xxl .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand-xxl .navbar-nav .dropdown-menu{position:absolute}.navbar-expand-xxl .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand-xxl .navbar-nav-scroll{overflow:visible}.navbar-expand-xxl .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand-xxl .navbar-toggler{display:none}.navbar-expand-xxl .offcanvas-header{display:none}.navbar-expand-xxl .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;-webkit-flex-grow:1;visibility:visible !important;background-color:rgba(0,0,0,0);border-right:0;border-left:0;transition:none;transform:none}.navbar-expand-xxl .offcanvas-top,.navbar-expand-xxl .offcanvas-bottom{height:auto;border-top:0;border-bottom:0}.navbar-expand-xxl .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}}.navbar-expand{flex-wrap:nowrap;-webkit-flex-wrap:nowrap;justify-content:flex-start;-webkit-justify-content:flex-start}.navbar-expand .navbar-nav{flex-direction:row;-webkit-flex-direction:row}.navbar-expand .navbar-nav .dropdown-menu{position:absolute}.navbar-expand .navbar-nav .nav-link{padding-right:.5rem;padding-left:.5rem}.navbar-expand .navbar-nav-scroll{overflow:visible}.navbar-expand .navbar-collapse{display:flex !important;display:-webkit-flex !important;flex-basis:auto;-webkit-flex-basis:auto}.navbar-expand .navbar-toggler{display:none}.navbar-expand .offcanvas-header{display:none}.navbar-expand .offcanvas{position:inherit;bottom:0;z-index:1000;flex-grow:1;-webkit-flex-grow:1;visibility:visible !important;background-color:rgba(0,0,0,0);border-right:0;border-left:0;transition:none;transform:none}.navbar-expand .offcanvas-top,.navbar-expand .offcanvas-bottom{height:auto;border-top:0;border-bottom:0}.navbar-expand .offcanvas-body{display:flex;display:-webkit-flex;flex-grow:0;-webkit-flex-grow:0;padding:0;overflow-y:visible}.navbar-light{background-color:#2780e3}.navbar-light .navbar-brand{color:#fdfeff}.navbar-light .navbar-brand:hover,.navbar-light .navbar-brand:focus{color:#fdfeff}.navbar-light .navbar-nav .nav-link{color:#fdfeff}.navbar-light .navbar-nav .nav-link:hover,.navbar-light .navbar-nav .nav-link:focus{color:rgba(253,254,255,.8)}.navbar-light .navbar-nav .nav-link.disabled{color:rgba(253,254,255,.75)}.navbar-light .navbar-nav .show>.nav-link,.navbar-light .navbar-nav .nav-link.active{color:#fdfeff}.navbar-light .navbar-toggler{color:#fdfeff;border-color:rgba(253,254,255,0)}.navbar-light .navbar-toggler-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='%23fdfeff' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.navbar-light .navbar-text{color:#fdfeff}.navbar-light .navbar-text a,.navbar-light .navbar-text a:hover,.navbar-light .navbar-text a:focus{color:#fdfeff}.navbar-dark{background-color:#2780e3}.navbar-dark .navbar-brand{color:#fdfeff}.navbar-dark .navbar-brand:hover,.navbar-dark .navbar-brand:focus{color:#fdfeff}.navbar-dark .navbar-nav .nav-link{color:#fdfeff}.navbar-dark .navbar-nav .nav-link:hover,.navbar-dark .navbar-nav .nav-link:focus{color:rgba(253,254,255,.8)}.navbar-dark .navbar-nav .nav-link.disabled{color:rgba(253,254,255,.75)}.navbar-dark .navbar-nav .show>.nav-link,.navbar-dark .navbar-nav .active>.nav-link,.navbar-dark .navbar-nav .nav-link.active{color:#fdfeff}.navbar-dark .navbar-toggler{color:#fdfeff;border-color:rgba(253,254,255,0)}.navbar-dark .navbar-toggler-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='%23fdfeff' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e")}.navbar-dark .navbar-text{color:#fdfeff}.navbar-dark .navbar-text a,.navbar-dark .navbar-text a:hover,.navbar-dark .navbar-text a:focus{color:#fdfeff}.card{position:relative;display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;min-width:0;word-wrap:break-word;background-color:#fff;background-clip:border-box;border:1px solid rgba(0,0,0,.125)}.card>hr{margin-right:0;margin-left:0}.card>.list-group{border-top:inherit;border-bottom:inherit}.card>.list-group:first-child{border-top-width:0}.card>.list-group:last-child{border-bottom-width:0}.card>.card-header+.list-group,.card>.list-group+.card-footer{border-top:0}.card-body{flex:1 1 auto;-webkit-flex:1 1 auto;padding:1rem 1rem}.card-title{margin-bottom:.5rem}.card-subtitle{margin-top:-0.25rem;margin-bottom:0}.card-text:last-child{margin-bottom:0}.card-link+.card-link{margin-left:1rem}.card-header{padding:.5rem 1rem;margin-bottom:0;background-color:#adb5bd;border-bottom:1px solid rgba(0,0,0,.125)}.card-footer{padding:.5rem 1rem;background-color:#adb5bd;border-top:1px solid rgba(0,0,0,.125)}.card-header-tabs{margin-right:-0.5rem;margin-bottom:-0.5rem;margin-left:-0.5rem;border-bottom:0}.card-header-pills{margin-right:-0.5rem;margin-left:-0.5rem}.card-img-overlay{position:absolute;top:0;right:0;bottom:0;left:0;padding:1rem}.card-img,.card-img-top,.card-img-bottom{width:100%}.card-group>.card{margin-bottom:.75rem}@media(min-width: 576px){.card-group{display:flex;display:-webkit-flex;flex-flow:row wrap;-webkit-flex-flow:row wrap}.card-group>.card{flex:1 0 0%;-webkit-flex:1 0 0%;margin-bottom:0}.card-group>.card+.card{margin-left:0;border-left:0}}.accordion-button{position:relative;display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;width:100%;padding:1rem 1.25rem;font-size:1rem;color:#373a3c;text-align:left;background-color:#fff;border:0;overflow-anchor:none;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out,border-radius .15s ease}@media(prefers-reduced-motion: reduce){.accordion-button{transition:none}}.accordion-button:not(.collapsed){color:#2373cc;background-color:#e9f2fc;box-shadow:inset 0 -1px 0 rgba(0,0,0,.125)}.accordion-button:not(.collapsed)::after{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%232373cc'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");transform:rotate(-180deg)}.accordion-button::after{flex-shrink:0;-webkit-flex-shrink:0;width:1.25rem;height:1.25rem;margin-left:auto;content:"";background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23373a3c'%3e%3cpath fill-rule='evenodd' d='M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e");background-repeat:no-repeat;background-size:1.25rem;transition:transform .2s ease-in-out}@media(prefers-reduced-motion: reduce){.accordion-button::after{transition:none}}.accordion-button:hover{z-index:2}.accordion-button:focus{z-index:3;border-color:#93c0f1;outline:0;box-shadow:0 0 0 .25rem rgba(39,128,227,.25)}.accordion-header{margin-bottom:0}.accordion-item{background-color:#fff;border:1px solid rgba(0,0,0,.125)}.accordion-item:not(:first-of-type){border-top:0}.accordion-body{padding:1rem 1.25rem}.accordion-flush .accordion-collapse{border-width:0}.accordion-flush .accordion-item{border-right:0;border-left:0}.accordion-flush .accordion-item:first-child{border-top:0}.accordion-flush .accordion-item:last-child{border-bottom:0}.breadcrumb{display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;padding:0 0;margin-bottom:1rem;list-style:none}.breadcrumb-item+.breadcrumb-item{padding-left:.5rem}.breadcrumb-item+.breadcrumb-item::before{float:left;padding-right:.5rem;color:#6c757d;content:var(--bs-breadcrumb-divider, ">") /* rtl: var(--bs-breadcrumb-divider, ">") */}.breadcrumb-item.active{color:#6c757d}.pagination{display:flex;display:-webkit-flex;padding-left:0;list-style:none}.page-link{position:relative;display:block;color:#2780e3;text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;background-color:#fff;border:1px solid #dee2e6;transition:color .15s ease-in-out,background-color .15s ease-in-out,border-color .15s ease-in-out,box-shadow .15s ease-in-out}@media(prefers-reduced-motion: reduce){.page-link{transition:none}}.page-link:hover{z-index:2;color:#1f66b6;background-color:#e9ecef;border-color:#dee2e6}.page-link:focus{z-index:3;color:#1f66b6;background-color:#e9ecef;outline:0;box-shadow:0 0 0 .25rem rgba(39,128,227,.25)}.page-item:not(:first-child) .page-link{margin-left:-1px}.page-item.active .page-link{z-index:3;color:#fff;background-color:#2780e3;border-color:#2780e3}.page-item.disabled .page-link{color:#6c757d;pointer-events:none;background-color:#fff;border-color:#dee2e6}.page-link{padding:.375rem .75rem}.pagination-lg .page-link{padding:.75rem 1.5rem;font-size:1.25rem}.pagination-sm .page-link{padding:.25rem .5rem;font-size:0.875rem}.badge{display:inline-block;padding:.35em .65em;font-size:0.75em;font-weight:700;line-height:1;color:#fff;text-align:center;white-space:nowrap;vertical-align:baseline}.badge:empty{display:none}.btn .badge{position:relative;top:-1px}.alert{position:relative;padding:1rem 1rem;margin-bottom:1rem;border:0 solid rgba(0,0,0,0)}.alert-heading{color:inherit}.alert-link{font-weight:700}.alert-dismissible{padding-right:3rem}.alert-dismissible .btn-close{position:absolute;top:0;right:0;z-index:2;padding:1.25rem 1rem}.alert-default{color:#212324;background-color:#d7d8d8;border-color:#c3c4c5}.alert-default .alert-link{color:#1a1c1d}.alert-primary{color:#174d88;background-color:#d4e6f9;border-color:#bed9f7}.alert-primary .alert-link{color:#123e6d}.alert-secondary{color:#212324;background-color:#d7d8d8;border-color:#c3c4c5}.alert-secondary .alert-link{color:#1a1c1d}.alert-success{color:#266d0e;background-color:#d9f0d1;border-color:#c5e9ba}.alert-success .alert-link{color:#1e570b}.alert-info{color:#5c3270;background-color:#ebddf1;border-color:#e0cceb}.alert-info .alert-link{color:#4a285a}.alert-warning{color:#99460e;background-color:#ffe3d1;border-color:#ffd6ba}.alert-warning .alert-link{color:#7a380b}.alert-danger{color:#902;background-color:#ffccd7;border-color:#ffb3c4}.alert-danger .alert-link{color:#7a001b}.alert-light{color:#959596;background-color:#fefefe;border-color:#fdfdfe}.alert-light .alert-link{color:#777778}.alert-dark{color:#212324;background-color:#d7d8d8;border-color:#c3c4c5}.alert-dark .alert-link{color:#1a1c1d}@keyframes progress-bar-stripes{0%{background-position-x:.5rem}}.progress{display:flex;display:-webkit-flex;height:.5rem;overflow:hidden;font-size:0.75rem;background-color:#e9ecef}.progress-bar{display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;justify-content:center;-webkit-justify-content:center;overflow:hidden;color:#fff;text-align:center;white-space:nowrap;background-color:#2780e3;transition:width .6s ease}@media(prefers-reduced-motion: reduce){.progress-bar{transition:none}}.progress-bar-striped{background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-size:.5rem .5rem}.progress-bar-animated{animation:1s linear infinite progress-bar-stripes}@media(prefers-reduced-motion: reduce){.progress-bar-animated{animation:none}}.list-group{display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;padding-left:0;margin-bottom:0}.list-group-numbered{list-style-type:none;counter-reset:section}.list-group-numbered>li::before{content:counters(section, ".") ". ";counter-increment:section}.list-group-item-action{width:100%;color:#495057;text-align:inherit}.list-group-item-action:hover,.list-group-item-action:focus{z-index:1;color:#495057;text-decoration:none;background-color:#f8f9fa}.list-group-item-action:active{color:#373a3c;background-color:#e9ecef}.list-group-item{position:relative;display:block;padding:.5rem 1rem;color:#212529;text-decoration:none;-webkit-text-decoration:none;-moz-text-decoration:none;-ms-text-decoration:none;-o-text-decoration:none;background-color:#fff;border:1px solid rgba(0,0,0,.125)}.list-group-item.disabled,.list-group-item:disabled{color:#6c757d;pointer-events:none;background-color:#fff}.list-group-item.active{z-index:2;color:#fff;background-color:#2780e3;border-color:#2780e3}.list-group-item+.list-group-item{border-top-width:0}.list-group-item+.list-group-item.active{margin-top:-1px;border-top-width:1px}.list-group-horizontal{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal>.list-group-item.active{margin-top:0}.list-group-horizontal>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}@media(min-width: 576px){.list-group-horizontal-sm{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-sm>.list-group-item.active{margin-top:0}.list-group-horizontal-sm>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-sm>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media(min-width: 768px){.list-group-horizontal-md{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-md>.list-group-item.active{margin-top:0}.list-group-horizontal-md>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-md>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media(min-width: 992px){.list-group-horizontal-lg{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-lg>.list-group-item.active{margin-top:0}.list-group-horizontal-lg>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-lg>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media(min-width: 1200px){.list-group-horizontal-xl{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-xl>.list-group-item.active{margin-top:0}.list-group-horizontal-xl>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-xl>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}@media(min-width: 1400px){.list-group-horizontal-xxl{flex-direction:row;-webkit-flex-direction:row}.list-group-horizontal-xxl>.list-group-item.active{margin-top:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item{border-top-width:1px;border-left-width:0}.list-group-horizontal-xxl>.list-group-item+.list-group-item.active{margin-left:-1px;border-left-width:1px}}.list-group-flush>.list-group-item{border-width:0 0 1px}.list-group-flush>.list-group-item:last-child{border-bottom-width:0}.list-group-item-default{color:#212324;background-color:#d7d8d8}.list-group-item-default.list-group-item-action:hover,.list-group-item-default.list-group-item-action:focus{color:#212324;background-color:#c2c2c2}.list-group-item-default.list-group-item-action.active{color:#fff;background-color:#212324;border-color:#212324}.list-group-item-primary{color:#174d88;background-color:#d4e6f9}.list-group-item-primary.list-group-item-action:hover,.list-group-item-primary.list-group-item-action:focus{color:#174d88;background-color:#bfcfe0}.list-group-item-primary.list-group-item-action.active{color:#fff;background-color:#174d88;border-color:#174d88}.list-group-item-secondary{color:#212324;background-color:#d7d8d8}.list-group-item-secondary.list-group-item-action:hover,.list-group-item-secondary.list-group-item-action:focus{color:#212324;background-color:#c2c2c2}.list-group-item-secondary.list-group-item-action.active{color:#fff;background-color:#212324;border-color:#212324}.list-group-item-success{color:#266d0e;background-color:#d9f0d1}.list-group-item-success.list-group-item-action:hover,.list-group-item-success.list-group-item-action:focus{color:#266d0e;background-color:#c3d8bc}.list-group-item-success.list-group-item-action.active{color:#fff;background-color:#266d0e;border-color:#266d0e}.list-group-item-info{color:#5c3270;background-color:#ebddf1}.list-group-item-info.list-group-item-action:hover,.list-group-item-info.list-group-item-action:focus{color:#5c3270;background-color:#d4c7d9}.list-group-item-info.list-group-item-action.active{color:#fff;background-color:#5c3270;border-color:#5c3270}.list-group-item-warning{color:#99460e;background-color:#ffe3d1}.list-group-item-warning.list-group-item-action:hover,.list-group-item-warning.list-group-item-action:focus{color:#99460e;background-color:#e6ccbc}.list-group-item-warning.list-group-item-action.active{color:#fff;background-color:#99460e;border-color:#99460e}.list-group-item-danger{color:#902;background-color:#ffccd7}.list-group-item-danger.list-group-item-action:hover,.list-group-item-danger.list-group-item-action:focus{color:#902;background-color:#e6b8c2}.list-group-item-danger.list-group-item-action.active{color:#fff;background-color:#902;border-color:#902}.list-group-item-light{color:#959596;background-color:#fefefe}.list-group-item-light.list-group-item-action:hover,.list-group-item-light.list-group-item-action:focus{color:#959596;background-color:#e5e5e5}.list-group-item-light.list-group-item-action.active{color:#fff;background-color:#959596;border-color:#959596}.list-group-item-dark{color:#212324;background-color:#d7d8d8}.list-group-item-dark.list-group-item-action:hover,.list-group-item-dark.list-group-item-action:focus{color:#212324;background-color:#c2c2c2}.list-group-item-dark.list-group-item-action.active{color:#fff;background-color:#212324;border-color:#212324}.btn-close{box-sizing:content-box;width:1em;height:1em;padding:.25em .25em;color:#000;background:rgba(0,0,0,0) url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 011.414 0L8 6.586 14.293.293a1 1 0 111.414 1.414L9.414 8l6.293 6.293a1 1 0 01-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 01-1.414-1.414L6.586 8 .293 1.707a1 1 0 010-1.414z'/%3e%3c/svg%3e") center/1em auto no-repeat;border:0;opacity:.5}.btn-close:hover{color:#000;text-decoration:none;opacity:.75}.btn-close:focus{outline:0;box-shadow:0 0 0 .25rem rgba(39,128,227,.25);opacity:1}.btn-close:disabled,.btn-close.disabled{pointer-events:none;user-select:none;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;-o-user-select:none;opacity:.25}.btn-close-white{filter:invert(1) grayscale(100%) brightness(200%)}.toast{width:350px;max-width:100%;font-size:0.875rem;pointer-events:auto;background-color:rgba(255,255,255,.85);background-clip:padding-box;border:1px solid rgba(0,0,0,.1);box-shadow:0 .5rem 1rem rgba(0,0,0,.15)}.toast.showing{opacity:0}.toast:not(.show){display:none}.toast-container{width:max-content;width:-webkit-max-content;width:-moz-max-content;width:-ms-max-content;width:-o-max-content;max-width:100%;pointer-events:none}.toast-container>:not(:last-child){margin-bottom:.75rem}.toast-header{display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;padding:.5rem .75rem;color:#6c757d;background-color:rgba(255,255,255,.85);background-clip:padding-box;border-bottom:1px solid rgba(0,0,0,.05)}.toast-header .btn-close{margin-right:-0.375rem;margin-left:.75rem}.toast-body{padding:.75rem;word-wrap:break-word}.modal{position:fixed;top:0;left:0;z-index:1055;display:none;width:100%;height:100%;overflow-x:hidden;overflow-y:auto;outline:0}.modal-dialog{position:relative;width:auto;margin:.5rem;pointer-events:none}.modal.fade .modal-dialog{transition:transform .3s ease-out;transform:translate(0, -50px)}@media(prefers-reduced-motion: reduce){.modal.fade .modal-dialog{transition:none}}.modal.show .modal-dialog{transform:none}.modal.modal-static .modal-dialog{transform:scale(1.02)}.modal-dialog-scrollable{height:calc(100% - 1rem)}.modal-dialog-scrollable .modal-content{max-height:100%;overflow:hidden}.modal-dialog-scrollable .modal-body{overflow-y:auto}.modal-dialog-centered{display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;min-height:calc(100% - 1rem)}.modal-content{position:relative;display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;width:100%;pointer-events:auto;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2);outline:0}.modal-backdrop{position:fixed;top:0;left:0;z-index:1050;width:100vw;height:100vh;background-color:#000}.modal-backdrop.fade{opacity:0}.modal-backdrop.show{opacity:.5}.modal-header{display:flex;display:-webkit-flex;flex-shrink:0;-webkit-flex-shrink:0;align-items:center;-webkit-align-items:center;justify-content:space-between;-webkit-justify-content:space-between;padding:1rem 1rem;border-bottom:1px solid #dee2e6}.modal-header .btn-close{padding:.5rem .5rem;margin:-0.5rem -0.5rem -0.5rem auto}.modal-title{margin-bottom:0;line-height:1.5}.modal-body{position:relative;flex:1 1 auto;-webkit-flex:1 1 auto;padding:1rem}.modal-footer{display:flex;display:-webkit-flex;flex-wrap:wrap;-webkit-flex-wrap:wrap;flex-shrink:0;-webkit-flex-shrink:0;align-items:center;-webkit-align-items:center;justify-content:flex-end;-webkit-justify-content:flex-end;padding:.75rem;border-top:1px solid #dee2e6}.modal-footer>*{margin:.25rem}@media(min-width: 576px){.modal-dialog{max-width:500px;margin:1.75rem auto}.modal-dialog-scrollable{height:calc(100% - 3.5rem)}.modal-dialog-centered{min-height:calc(100% - 3.5rem)}.modal-sm{max-width:300px}}@media(min-width: 992px){.modal-lg,.modal-xl{max-width:800px}}@media(min-width: 1200px){.modal-xl{max-width:1140px}}.modal-fullscreen{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen .modal-content{height:100%;border:0}.modal-fullscreen .modal-body{overflow-y:auto}@media(max-width: 575.98px){.modal-fullscreen-sm-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-sm-down .modal-content{height:100%;border:0}.modal-fullscreen-sm-down .modal-body{overflow-y:auto}}@media(max-width: 767.98px){.modal-fullscreen-md-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-md-down .modal-content{height:100%;border:0}.modal-fullscreen-md-down .modal-body{overflow-y:auto}}@media(max-width: 991.98px){.modal-fullscreen-lg-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-lg-down .modal-content{height:100%;border:0}.modal-fullscreen-lg-down .modal-body{overflow-y:auto}}@media(max-width: 1199.98px){.modal-fullscreen-xl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xl-down .modal-content{height:100%;border:0}.modal-fullscreen-xl-down .modal-body{overflow-y:auto}}@media(max-width: 1399.98px){.modal-fullscreen-xxl-down{width:100vw;max-width:none;height:100%;margin:0}.modal-fullscreen-xxl-down .modal-content{height:100%;border:0}.modal-fullscreen-xxl-down .modal-body{overflow-y:auto}}.tooltip{position:absolute;z-index:1080;display:block;margin:0;font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.7;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:0.875rem;word-wrap:break-word;opacity:0}.tooltip.show{opacity:.9}.tooltip .tooltip-arrow{position:absolute;display:block;width:.8rem;height:.4rem}.tooltip .tooltip-arrow::before{position:absolute;content:"";border-color:rgba(0,0,0,0);border-style:solid}.bs-tooltip-top,.bs-tooltip-auto[data-popper-placement^=top]{padding:.4rem 0}.bs-tooltip-top .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow{bottom:0}.bs-tooltip-top .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=top] .tooltip-arrow::before{top:-1px;border-width:.4rem .4rem 0;border-top-color:#000}.bs-tooltip-end,.bs-tooltip-auto[data-popper-placement^=right]{padding:0 .4rem}.bs-tooltip-end .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow{left:0;width:.4rem;height:.8rem}.bs-tooltip-end .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=right] .tooltip-arrow::before{right:-1px;border-width:.4rem .4rem .4rem 0;border-right-color:#000}.bs-tooltip-bottom,.bs-tooltip-auto[data-popper-placement^=bottom]{padding:.4rem 0}.bs-tooltip-bottom .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow{top:0}.bs-tooltip-bottom .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=bottom] .tooltip-arrow::before{bottom:-1px;border-width:0 .4rem .4rem;border-bottom-color:#000}.bs-tooltip-start,.bs-tooltip-auto[data-popper-placement^=left]{padding:0 .4rem}.bs-tooltip-start .tooltip-arrow,.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow{right:0;width:.4rem;height:.8rem}.bs-tooltip-start .tooltip-arrow::before,.bs-tooltip-auto[data-popper-placement^=left] .tooltip-arrow::before{left:-1px;border-width:.4rem 0 .4rem .4rem;border-left-color:#000}.tooltip-inner{max-width:200px;padding:.25rem .5rem;color:#fff;text-align:center;background-color:#000}.popover{position:absolute;top:0;left:0 /* rtl:ignore */;z-index:1070;display:block;max-width:276px;font-family:var(--bs-font-sans-serif);font-style:normal;font-weight:400;line-height:1.7;text-align:left;text-align:start;text-decoration:none;text-shadow:none;text-transform:none;letter-spacing:normal;word-break:normal;word-spacing:normal;white-space:normal;line-break:auto;font-size:0.875rem;word-wrap:break-word;background-color:#fff;background-clip:padding-box;border:1px solid rgba(0,0,0,.2)}.popover .popover-arrow{position:absolute;display:block;width:1rem;height:.5rem}.popover .popover-arrow::before,.popover .popover-arrow::after{position:absolute;display:block;content:"";border-color:rgba(0,0,0,0);border-style:solid}.bs-popover-top>.popover-arrow,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow{bottom:calc(-0.5rem - 1px)}.bs-popover-top>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::before{bottom:0;border-width:.5rem .5rem 0;border-top-color:rgba(0,0,0,.25)}.bs-popover-top>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=top]>.popover-arrow::after{bottom:1px;border-width:.5rem .5rem 0;border-top-color:#fff}.bs-popover-end>.popover-arrow,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow{left:calc(-0.5rem - 1px);width:.5rem;height:1rem}.bs-popover-end>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::before{left:0;border-width:.5rem .5rem .5rem 0;border-right-color:rgba(0,0,0,.25)}.bs-popover-end>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=right]>.popover-arrow::after{left:1px;border-width:.5rem .5rem .5rem 0;border-right-color:#fff}.bs-popover-bottom>.popover-arrow,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow{top:calc(-0.5rem - 1px)}.bs-popover-bottom>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::before{top:0;border-width:0 .5rem .5rem .5rem;border-bottom-color:rgba(0,0,0,.25)}.bs-popover-bottom>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=bottom]>.popover-arrow::after{top:1px;border-width:0 .5rem .5rem .5rem;border-bottom-color:#fff}.bs-popover-bottom .popover-header::before,.bs-popover-auto[data-popper-placement^=bottom] .popover-header::before{position:absolute;top:0;left:50%;display:block;width:1rem;margin-left:-0.5rem;content:"";border-bottom:1px solid #f0f0f0}.bs-popover-start>.popover-arrow,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow{right:calc(-0.5rem - 1px);width:.5rem;height:1rem}.bs-popover-start>.popover-arrow::before,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::before{right:0;border-width:.5rem 0 .5rem .5rem;border-left-color:rgba(0,0,0,.25)}.bs-popover-start>.popover-arrow::after,.bs-popover-auto[data-popper-placement^=left]>.popover-arrow::after{right:1px;border-width:.5rem 0 .5rem .5rem;border-left-color:#fff}.popover-header{padding:.5rem 1rem;margin-bottom:0;font-size:1rem;background-color:#f0f0f0;border-bottom:1px solid rgba(0,0,0,.2)}.popover-header:empty{display:none}.popover-body{padding:1rem 1rem;color:#373a3c}.carousel{position:relative}.carousel.pointer-event{touch-action:pan-y;-webkit-touch-action:pan-y;-moz-touch-action:pan-y;-ms-touch-action:pan-y;-o-touch-action:pan-y}.carousel-inner{position:relative;width:100%;overflow:hidden}.carousel-inner::after{display:block;clear:both;content:""}.carousel-item{position:relative;display:none;float:left;width:100%;margin-right:-100%;backface-visibility:hidden;-webkit-backface-visibility:hidden;-moz-backface-visibility:hidden;-ms-backface-visibility:hidden;-o-backface-visibility:hidden;transition:transform .6s ease-in-out}@media(prefers-reduced-motion: reduce){.carousel-item{transition:none}}.carousel-item.active,.carousel-item-next,.carousel-item-prev{display:block}.carousel-item-next:not(.carousel-item-start),.active.carousel-item-end{transform:translateX(100%)}.carousel-item-prev:not(.carousel-item-end),.active.carousel-item-start{transform:translateX(-100%)}.carousel-fade .carousel-item{opacity:0;transition-property:opacity;transform:none}.carousel-fade .carousel-item.active,.carousel-fade .carousel-item-next.carousel-item-start,.carousel-fade .carousel-item-prev.carousel-item-end{z-index:1;opacity:1}.carousel-fade .active.carousel-item-start,.carousel-fade .active.carousel-item-end{z-index:0;opacity:0;transition:opacity 0s .6s}@media(prefers-reduced-motion: reduce){.carousel-fade .active.carousel-item-start,.carousel-fade .active.carousel-item-end{transition:none}}.carousel-control-prev,.carousel-control-next{position:absolute;top:0;bottom:0;z-index:1;display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;justify-content:center;-webkit-justify-content:center;width:15%;padding:0;color:#fff;text-align:center;background:none;border:0;opacity:.5;transition:opacity .15s ease}@media(prefers-reduced-motion: reduce){.carousel-control-prev,.carousel-control-next{transition:none}}.carousel-control-prev:hover,.carousel-control-prev:focus,.carousel-control-next:hover,.carousel-control-next:focus{color:#fff;text-decoration:none;outline:0;opacity:.9}.carousel-control-prev{left:0}.carousel-control-next{right:0}.carousel-control-prev-icon,.carousel-control-next-icon{display:inline-block;width:2rem;height:2rem;background-repeat:no-repeat;background-position:50%;background-size:100% 100%}.carousel-control-prev-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M11.354 1.646a.5.5 0 0 1 0 .708L5.707 8l5.647 5.646a.5.5 0 0 1-.708.708l-6-6a.5.5 0 0 1 0-.708l6-6a.5.5 0 0 1 .708 0z'/%3e%3c/svg%3e")}.carousel-control-next-icon{background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23fff'%3e%3cpath d='M4.646 1.646a.5.5 0 0 1 .708 0l6 6a.5.5 0 0 1 0 .708l-6 6a.5.5 0 0 1-.708-.708L10.293 8 4.646 2.354a.5.5 0 0 1 0-.708z'/%3e%3c/svg%3e")}.carousel-indicators{position:absolute;right:0;bottom:0;left:0;z-index:2;display:flex;display:-webkit-flex;justify-content:center;-webkit-justify-content:center;padding:0;margin-right:15%;margin-bottom:1rem;margin-left:15%;list-style:none}.carousel-indicators [data-bs-target]{box-sizing:content-box;flex:0 1 auto;-webkit-flex:0 1 auto;width:30px;height:3px;padding:0;margin-right:3px;margin-left:3px;text-indent:-999px;cursor:pointer;background-color:#fff;background-clip:padding-box;border:0;border-top:10px solid rgba(0,0,0,0);border-bottom:10px solid rgba(0,0,0,0);opacity:.5;transition:opacity .6s ease}@media(prefers-reduced-motion: reduce){.carousel-indicators [data-bs-target]{transition:none}}.carousel-indicators .active{opacity:1}.carousel-caption{position:absolute;right:15%;bottom:1.25rem;left:15%;padding-top:1.25rem;padding-bottom:1.25rem;color:#fff;text-align:center}.carousel-dark .carousel-control-prev-icon,.carousel-dark .carousel-control-next-icon{filter:invert(1) grayscale(100)}.carousel-dark .carousel-indicators [data-bs-target]{background-color:#000}.carousel-dark .carousel-caption{color:#000}@keyframes spinner-border{to{transform:rotate(360deg) /* rtl:ignore */}}.spinner-border{display:inline-block;width:2rem;height:2rem;vertical-align:-0.125em;border:.25em solid currentColor;border-right-color:rgba(0,0,0,0);border-radius:50%;animation:.75s linear infinite spinner-border}.spinner-border-sm{width:1rem;height:1rem;border-width:.2em}@keyframes spinner-grow{0%{transform:scale(0)}50%{opacity:1;transform:none}}.spinner-grow{display:inline-block;width:2rem;height:2rem;vertical-align:-0.125em;background-color:currentColor;border-radius:50%;opacity:0;animation:.75s linear infinite spinner-grow}.spinner-grow-sm{width:1rem;height:1rem}@media(prefers-reduced-motion: reduce){.spinner-border,.spinner-grow{animation-duration:1.5s;-webkit-animation-duration:1.5s;-moz-animation-duration:1.5s;-ms-animation-duration:1.5s;-o-animation-duration:1.5s}}.offcanvas{position:fixed;bottom:0;z-index:1045;display:flex;display:-webkit-flex;flex-direction:column;-webkit-flex-direction:column;max-width:100%;visibility:hidden;background-color:#fff;background-clip:padding-box;outline:0;transition:transform .3s ease-in-out}@media(prefers-reduced-motion: reduce){.offcanvas{transition:none}}.offcanvas-backdrop{position:fixed;top:0;left:0;z-index:1040;width:100vw;height:100vh;background-color:#000}.offcanvas-backdrop.fade{opacity:0}.offcanvas-backdrop.show{opacity:.5}.offcanvas-header{display:flex;display:-webkit-flex;align-items:center;-webkit-align-items:center;justify-content:space-between;-webkit-justify-content:space-between;padding:1rem 1rem}.offcanvas-header .btn-close{padding:.5rem .5rem;margin-top:-0.5rem;margin-right:-0.5rem;margin-bottom:-0.5rem}.offcanvas-title{margin-bottom:0;line-height:1.5}.offcanvas-body{flex-grow:1;-webkit-flex-grow:1;padding:1rem 1rem;overflow-y:auto}.offcanvas-start{top:0;left:0;width:400px;border-right:1px solid rgba(0,0,0,.2);transform:translateX(-100%)}.offcanvas-end{top:0;right:0;width:400px;border-left:1px solid rgba(0,0,0,.2);transform:translateX(100%)}.offcanvas-top{top:0;right:0;left:0;height:30vh;max-height:100%;border-bottom:1px solid rgba(0,0,0,.2);transform:translateY(-100%)}.offcanvas-bottom{right:0;left:0;height:30vh;max-height:100%;border-top:1px solid rgba(0,0,0,.2);transform:translateY(100%)}.offcanvas.show{transform:none}.placeholder{display:inline-block;min-height:1em;vertical-align:middle;cursor:wait;background-color:currentColor;opacity:.5}.placeholder.btn::before{display:inline-block;content:""}.placeholder-xs{min-height:.6em}.placeholder-sm{min-height:.8em}.placeholder-lg{min-height:1.2em}.placeholder-glow .placeholder{animation:placeholder-glow 2s ease-in-out infinite}@keyframes placeholder-glow{50%{opacity:.2}}.placeholder-wave{mask-image:linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%);-webkit-mask-image:linear-gradient(130deg, #000 55%, rgba(0, 0, 0, 0.8) 75%, #000 95%);mask-size:200% 100%;-webkit-mask-size:200% 100%;animation:placeholder-wave 2s linear infinite}@keyframes placeholder-wave{100%{mask-position:-200% 0%;-webkit-mask-position:-200% 0%}}.clearfix::after{display:block;clear:both;content:""}.link-default{color:#373a3c}.link-default:hover,.link-default:focus{color:#2c2e30}.link-primary{color:#2780e3}.link-primary:hover,.link-primary:focus{color:#1f66b6}.link-secondary{color:#373a3c}.link-secondary:hover,.link-secondary:focus{color:#2c2e30}.link-success{color:#3fb618}.link-success:hover,.link-success:focus{color:#329213}.link-info{color:#9954bb}.link-info:hover,.link-info:focus{color:#7a4396}.link-warning{color:#ff7518}.link-warning:hover,.link-warning:focus{color:#cc5e13}.link-danger{color:#ff0039}.link-danger:hover,.link-danger:focus{color:#cc002e}.link-light{color:#f8f9fa}.link-light:hover,.link-light:focus{color:#f9fafb}.link-dark{color:#373a3c}.link-dark:hover,.link-dark:focus{color:#2c2e30}.ratio{position:relative;width:100%}.ratio::before{display:block;padding-top:var(--bs-aspect-ratio);content:""}.ratio>*{position:absolute;top:0;left:0;width:100%;height:100%}.ratio-1x1{--bs-aspect-ratio: 100%}.ratio-4x3{--bs-aspect-ratio: 75%}.ratio-16x9{--bs-aspect-ratio: 56.25%}.ratio-21x9{--bs-aspect-ratio: 42.8571428571%}.fixed-top{position:fixed;top:0;right:0;left:0;z-index:1030}.fixed-bottom{position:fixed;right:0;bottom:0;left:0;z-index:1030}.sticky-top{position:sticky;top:0;z-index:1020}@media(min-width: 576px){.sticky-sm-top{position:sticky;top:0;z-index:1020}}@media(min-width: 768px){.sticky-md-top{position:sticky;top:0;z-index:1020}}@media(min-width: 992px){.sticky-lg-top{position:sticky;top:0;z-index:1020}}@media(min-width: 1200px){.sticky-xl-top{position:sticky;top:0;z-index:1020}}@media(min-width: 1400px){.sticky-xxl-top{position:sticky;top:0;z-index:1020}}.hstack{display:flex;display:-webkit-flex;flex-direction:row;-webkit-flex-direction:row;align-items:center;-webkit-align-items:center;align-self:stretch;-webkit-align-self:stretch}.vstack{display:flex;display:-webkit-flex;flex:1 1 auto;-webkit-flex:1 1 auto;flex-direction:column;-webkit-flex-direction:column;align-self:stretch;-webkit-align-self:stretch}.visually-hidden,.visually-hidden-focusable:not(:focus):not(:focus-within){position:absolute !important;width:1px !important;height:1px !important;padding:0 !important;margin:-1px !important;overflow:hidden !important;clip:rect(0, 0, 0, 0) !important;white-space:nowrap !important;border:0 !important}.stretched-link::after{position:absolute;top:0;right:0;bottom:0;left:0;z-index:1;content:""}.text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.vr{display:inline-block;align-self:stretch;-webkit-align-self:stretch;width:1px;min-height:1em;background-color:currentColor;opacity:.25}.align-baseline{vertical-align:baseline !important}.align-top{vertical-align:top !important}.align-middle{vertical-align:middle !important}.align-bottom{vertical-align:bottom !important}.align-text-bottom{vertical-align:text-bottom !important}.align-text-top{vertical-align:text-top !important}.float-start{float:left !important}.float-end{float:right !important}.float-none{float:none !important}.opacity-0{opacity:0 !important}.opacity-25{opacity:.25 !important}.opacity-50{opacity:.5 !important}.opacity-75{opacity:.75 !important}.opacity-100{opacity:1 !important}.overflow-auto{overflow:auto !important}.overflow-hidden{overflow:hidden !important}.overflow-visible{overflow:visible !important}.overflow-scroll{overflow:scroll !important}.d-inline{display:inline !important}.d-inline-block{display:inline-block !important}.d-block{display:block !important}.d-grid{display:grid !important}.d-table{display:table !important}.d-table-row{display:table-row !important}.d-table-cell{display:table-cell !important}.d-flex{display:flex !important}.d-inline-flex{display:inline-flex !important}.d-none{display:none !important}.shadow{box-shadow:0 .5rem 1rem rgba(0,0,0,.15) !important}.shadow-sm{box-shadow:0 .125rem .25rem rgba(0,0,0,.075) !important}.shadow-lg{box-shadow:0 1rem 3rem rgba(0,0,0,.175) !important}.shadow-none{box-shadow:none !important}.position-static{position:static !important}.position-relative{position:relative !important}.position-absolute{position:absolute !important}.position-fixed{position:fixed !important}.position-sticky{position:sticky !important}.top-0{top:0 !important}.top-50{top:50% !important}.top-100{top:100% !important}.bottom-0{bottom:0 !important}.bottom-50{bottom:50% !important}.bottom-100{bottom:100% !important}.start-0{left:0 !important}.start-50{left:50% !important}.start-100{left:100% !important}.end-0{right:0 !important}.end-50{right:50% !important}.end-100{right:100% !important}.translate-middle{transform:translate(-50%, -50%) !important}.translate-middle-x{transform:translateX(-50%) !important}.translate-middle-y{transform:translateY(-50%) !important}.border{border:1px solid #dee2e6 !important}.border-0{border:0 !important}.border-top{border-top:1px solid #dee2e6 !important}.border-top-0{border-top:0 !important}.border-end{border-right:1px solid #dee2e6 !important}.border-end-0{border-right:0 !important}.border-bottom{border-bottom:1px solid #dee2e6 !important}.border-bottom-0{border-bottom:0 !important}.border-start{border-left:1px solid #dee2e6 !important}.border-start-0{border-left:0 !important}.border-default{border-color:#373a3c !important}.border-primary{border-color:#2780e3 !important}.border-secondary{border-color:#373a3c !important}.border-success{border-color:#3fb618 !important}.border-info{border-color:#9954bb !important}.border-warning{border-color:#ff7518 !important}.border-danger{border-color:#ff0039 !important}.border-light{border-color:#f8f9fa !important}.border-dark{border-color:#373a3c !important}.border-white{border-color:#fff !important}.border-1{border-width:1px !important}.border-2{border-width:2px !important}.border-3{border-width:3px !important}.border-4{border-width:4px !important}.border-5{border-width:5px !important}.w-25{width:25% !important}.w-50{width:50% !important}.w-75{width:75% !important}.w-100{width:100% !important}.w-auto{width:auto !important}.mw-100{max-width:100% !important}.vw-100{width:100vw !important}.min-vw-100{min-width:100vw !important}.h-25{height:25% !important}.h-50{height:50% !important}.h-75{height:75% !important}.h-100{height:100% !important}.h-auto{height:auto !important}.mh-100{max-height:100% !important}.vh-100{height:100vh !important}.min-vh-100{min-height:100vh !important}.flex-fill{flex:1 1 auto !important}.flex-row{flex-direction:row !important}.flex-column{flex-direction:column !important}.flex-row-reverse{flex-direction:row-reverse !important}.flex-column-reverse{flex-direction:column-reverse !important}.flex-grow-0{flex-grow:0 !important}.flex-grow-1{flex-grow:1 !important}.flex-shrink-0{flex-shrink:0 !important}.flex-shrink-1{flex-shrink:1 !important}.flex-wrap{flex-wrap:wrap !important}.flex-nowrap{flex-wrap:nowrap !important}.flex-wrap-reverse{flex-wrap:wrap-reverse !important}.gap-0{gap:0 !important}.gap-1{gap:.25rem !important}.gap-2{gap:.5rem !important}.gap-3{gap:1rem !important}.gap-4{gap:1.5rem !important}.gap-5{gap:3rem !important}.justify-content-start{justify-content:flex-start !important}.justify-content-end{justify-content:flex-end !important}.justify-content-center{justify-content:center !important}.justify-content-between{justify-content:space-between !important}.justify-content-around{justify-content:space-around !important}.justify-content-evenly{justify-content:space-evenly !important}.align-items-start{align-items:flex-start !important}.align-items-end{align-items:flex-end !important}.align-items-center{align-items:center !important}.align-items-baseline{align-items:baseline !important}.align-items-stretch{align-items:stretch !important}.align-content-start{align-content:flex-start !important}.align-content-end{align-content:flex-end !important}.align-content-center{align-content:center !important}.align-content-between{align-content:space-between !important}.align-content-around{align-content:space-around !important}.align-content-stretch{align-content:stretch !important}.align-self-auto{align-self:auto !important}.align-self-start{align-self:flex-start !important}.align-self-end{align-self:flex-end !important}.align-self-center{align-self:center !important}.align-self-baseline{align-self:baseline !important}.align-self-stretch{align-self:stretch !important}.order-first{order:-1 !important}.order-0{order:0 !important}.order-1{order:1 !important}.order-2{order:2 !important}.order-3{order:3 !important}.order-4{order:4 !important}.order-5{order:5 !important}.order-last{order:6 !important}.m-0{margin:0 !important}.m-1{margin:.25rem !important}.m-2{margin:.5rem !important}.m-3{margin:1rem !important}.m-4{margin:1.5rem !important}.m-5{margin:3rem !important}.m-auto{margin:auto !important}.mx-0{margin-right:0 !important;margin-left:0 !important}.mx-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-3{margin-right:1rem !important;margin-left:1rem !important}.mx-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-5{margin-right:3rem !important;margin-left:3rem !important}.mx-auto{margin-right:auto !important;margin-left:auto !important}.my-0{margin-top:0 !important;margin-bottom:0 !important}.my-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-0{margin-top:0 !important}.mt-1{margin-top:.25rem !important}.mt-2{margin-top:.5rem !important}.mt-3{margin-top:1rem !important}.mt-4{margin-top:1.5rem !important}.mt-5{margin-top:3rem !important}.mt-auto{margin-top:auto !important}.me-0{margin-right:0 !important}.me-1{margin-right:.25rem !important}.me-2{margin-right:.5rem !important}.me-3{margin-right:1rem !important}.me-4{margin-right:1.5rem !important}.me-5{margin-right:3rem !important}.me-auto{margin-right:auto !important}.mb-0{margin-bottom:0 !important}.mb-1{margin-bottom:.25rem !important}.mb-2{margin-bottom:.5rem !important}.mb-3{margin-bottom:1rem !important}.mb-4{margin-bottom:1.5rem !important}.mb-5{margin-bottom:3rem !important}.mb-auto{margin-bottom:auto !important}.ms-0{margin-left:0 !important}.ms-1{margin-left:.25rem !important}.ms-2{margin-left:.5rem !important}.ms-3{margin-left:1rem !important}.ms-4{margin-left:1.5rem !important}.ms-5{margin-left:3rem !important}.ms-auto{margin-left:auto !important}.p-0{padding:0 !important}.p-1{padding:.25rem !important}.p-2{padding:.5rem !important}.p-3{padding:1rem !important}.p-4{padding:1.5rem !important}.p-5{padding:3rem !important}.px-0{padding-right:0 !important;padding-left:0 !important}.px-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-3{padding-right:1rem !important;padding-left:1rem !important}.px-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-5{padding-right:3rem !important;padding-left:3rem !important}.py-0{padding-top:0 !important;padding-bottom:0 !important}.py-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-0{padding-top:0 !important}.pt-1{padding-top:.25rem !important}.pt-2{padding-top:.5rem !important}.pt-3{padding-top:1rem !important}.pt-4{padding-top:1.5rem !important}.pt-5{padding-top:3rem !important}.pe-0{padding-right:0 !important}.pe-1{padding-right:.25rem !important}.pe-2{padding-right:.5rem !important}.pe-3{padding-right:1rem !important}.pe-4{padding-right:1.5rem !important}.pe-5{padding-right:3rem !important}.pb-0{padding-bottom:0 !important}.pb-1{padding-bottom:.25rem !important}.pb-2{padding-bottom:.5rem !important}.pb-3{padding-bottom:1rem !important}.pb-4{padding-bottom:1.5rem !important}.pb-5{padding-bottom:3rem !important}.ps-0{padding-left:0 !important}.ps-1{padding-left:.25rem !important}.ps-2{padding-left:.5rem !important}.ps-3{padding-left:1rem !important}.ps-4{padding-left:1.5rem !important}.ps-5{padding-left:3rem !important}.font-monospace{font-family:var(--bs-font-monospace) !important}.fs-1{font-size:calc(1.325rem + 0.9vw) !important}.fs-2{font-size:calc(1.29rem + 0.48vw) !important}.fs-3{font-size:calc(1.27rem + 0.24vw) !important}.fs-4{font-size:1.25rem !important}.fs-5{font-size:1.1rem !important}.fs-6{font-size:1rem !important}.fst-italic{font-style:italic !important}.fst-normal{font-style:normal !important}.fw-light{font-weight:300 !important}.fw-lighter{font-weight:lighter !important}.fw-normal{font-weight:400 !important}.fw-bold{font-weight:700 !important}.fw-bolder{font-weight:bolder !important}.lh-1{line-height:1 !important}.lh-sm{line-height:1.25 !important}.lh-base{line-height:1.7 !important}.lh-lg{line-height:2 !important}.text-start{text-align:left !important}.text-end{text-align:right !important}.text-center{text-align:center !important}.text-decoration-none{text-decoration:none !important}.text-decoration-underline{text-decoration:underline !important}.text-decoration-line-through{text-decoration:line-through !important}.text-lowercase{text-transform:lowercase !important}.text-uppercase{text-transform:uppercase !important}.text-capitalize{text-transform:capitalize !important}.text-wrap{white-space:normal !important}.text-nowrap{white-space:nowrap !important}.text-break{word-wrap:break-word !important;word-break:break-word !important}.text-default{--bs-text-opacity: 1;color:rgba(var(--bs-default-rgb), var(--bs-text-opacity)) !important}.text-primary{--bs-text-opacity: 1;color:rgba(var(--bs-primary-rgb), var(--bs-text-opacity)) !important}.text-secondary{--bs-text-opacity: 1;color:rgba(var(--bs-secondary-rgb), var(--bs-text-opacity)) !important}.text-success{--bs-text-opacity: 1;color:rgba(var(--bs-success-rgb), var(--bs-text-opacity)) !important}.text-info{--bs-text-opacity: 1;color:rgba(var(--bs-info-rgb), var(--bs-text-opacity)) !important}.text-warning{--bs-text-opacity: 1;color:rgba(var(--bs-warning-rgb), var(--bs-text-opacity)) !important}.text-danger{--bs-text-opacity: 1;color:rgba(var(--bs-danger-rgb), var(--bs-text-opacity)) !important}.text-light{--bs-text-opacity: 1;color:rgba(var(--bs-light-rgb), var(--bs-text-opacity)) !important}.text-dark{--bs-text-opacity: 1;color:rgba(var(--bs-dark-rgb), var(--bs-text-opacity)) !important}.text-black{--bs-text-opacity: 1;color:rgba(var(--bs-black-rgb), var(--bs-text-opacity)) !important}.text-white{--bs-text-opacity: 1;color:rgba(var(--bs-white-rgb), var(--bs-text-opacity)) !important}.text-body{--bs-text-opacity: 1;color:rgba(var(--bs-body-color-rgb), var(--bs-text-opacity)) !important}.text-muted{--bs-text-opacity: 1;color:#6c757d !important}.text-black-50{--bs-text-opacity: 1;color:rgba(0,0,0,.5) !important}.text-white-50{--bs-text-opacity: 1;color:rgba(255,255,255,.5) !important}.text-reset{--bs-text-opacity: 1;color:inherit !important}.text-opacity-25{--bs-text-opacity: 0.25}.text-opacity-50{--bs-text-opacity: 0.5}.text-opacity-75{--bs-text-opacity: 0.75}.text-opacity-100{--bs-text-opacity: 1}.bg-default{--bs-bg-opacity: 1;background-color:rgba(var(--bs-default-rgb), var(--bs-bg-opacity)) !important}.bg-primary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-primary-rgb), var(--bs-bg-opacity)) !important}.bg-secondary{--bs-bg-opacity: 1;background-color:rgba(var(--bs-secondary-rgb), var(--bs-bg-opacity)) !important}.bg-success{--bs-bg-opacity: 1;background-color:rgba(var(--bs-success-rgb), var(--bs-bg-opacity)) !important}.bg-info{--bs-bg-opacity: 1;background-color:rgba(var(--bs-info-rgb), var(--bs-bg-opacity)) !important}.bg-warning{--bs-bg-opacity: 1;background-color:rgba(var(--bs-warning-rgb), var(--bs-bg-opacity)) !important}.bg-danger{--bs-bg-opacity: 1;background-color:rgba(var(--bs-danger-rgb), var(--bs-bg-opacity)) !important}.bg-light{--bs-bg-opacity: 1;background-color:rgba(var(--bs-light-rgb), var(--bs-bg-opacity)) !important}.bg-dark{--bs-bg-opacity: 1;background-color:rgba(var(--bs-dark-rgb), var(--bs-bg-opacity)) !important}.bg-black{--bs-bg-opacity: 1;background-color:rgba(var(--bs-black-rgb), var(--bs-bg-opacity)) !important}.bg-white{--bs-bg-opacity: 1;background-color:rgba(var(--bs-white-rgb), var(--bs-bg-opacity)) !important}.bg-body{--bs-bg-opacity: 1;background-color:rgba(var(--bs-body-bg-rgb), var(--bs-bg-opacity)) !important}.bg-transparent{--bs-bg-opacity: 1;background-color:rgba(0,0,0,0) !important}.bg-opacity-10{--bs-bg-opacity: 0.1}.bg-opacity-25{--bs-bg-opacity: 0.25}.bg-opacity-50{--bs-bg-opacity: 0.5}.bg-opacity-75{--bs-bg-opacity: 0.75}.bg-opacity-100{--bs-bg-opacity: 1}.bg-gradient{background-image:var(--bs-gradient) !important}.user-select-all{user-select:all !important}.user-select-auto{user-select:auto !important}.user-select-none{user-select:none !important}.pe-none{pointer-events:none !important}.pe-auto{pointer-events:auto !important}.rounded{border-radius:.25rem !important}.rounded-0{border-radius:0 !important}.rounded-1{border-radius:.2em !important}.rounded-2{border-radius:.25rem !important}.rounded-3{border-radius:.3rem !important}.rounded-circle{border-radius:50% !important}.rounded-pill{border-radius:50rem !important}.rounded-top{border-top-left-radius:.25rem !important;border-top-right-radius:.25rem !important}.rounded-end{border-top-right-radius:.25rem !important;border-bottom-right-radius:.25rem !important}.rounded-bottom{border-bottom-right-radius:.25rem !important;border-bottom-left-radius:.25rem !important}.rounded-start{border-bottom-left-radius:.25rem !important;border-top-left-radius:.25rem !important}.visible{visibility:visible !important}.invisible{visibility:hidden !important}@media(min-width: 576px){.float-sm-start{float:left !important}.float-sm-end{float:right !important}.float-sm-none{float:none !important}.d-sm-inline{display:inline !important}.d-sm-inline-block{display:inline-block !important}.d-sm-block{display:block !important}.d-sm-grid{display:grid !important}.d-sm-table{display:table !important}.d-sm-table-row{display:table-row !important}.d-sm-table-cell{display:table-cell !important}.d-sm-flex{display:flex !important}.d-sm-inline-flex{display:inline-flex !important}.d-sm-none{display:none !important}.flex-sm-fill{flex:1 1 auto !important}.flex-sm-row{flex-direction:row !important}.flex-sm-column{flex-direction:column !important}.flex-sm-row-reverse{flex-direction:row-reverse !important}.flex-sm-column-reverse{flex-direction:column-reverse !important}.flex-sm-grow-0{flex-grow:0 !important}.flex-sm-grow-1{flex-grow:1 !important}.flex-sm-shrink-0{flex-shrink:0 !important}.flex-sm-shrink-1{flex-shrink:1 !important}.flex-sm-wrap{flex-wrap:wrap !important}.flex-sm-nowrap{flex-wrap:nowrap !important}.flex-sm-wrap-reverse{flex-wrap:wrap-reverse !important}.gap-sm-0{gap:0 !important}.gap-sm-1{gap:.25rem !important}.gap-sm-2{gap:.5rem !important}.gap-sm-3{gap:1rem !important}.gap-sm-4{gap:1.5rem !important}.gap-sm-5{gap:3rem !important}.justify-content-sm-start{justify-content:flex-start !important}.justify-content-sm-end{justify-content:flex-end !important}.justify-content-sm-center{justify-content:center !important}.justify-content-sm-between{justify-content:space-between !important}.justify-content-sm-around{justify-content:space-around !important}.justify-content-sm-evenly{justify-content:space-evenly !important}.align-items-sm-start{align-items:flex-start !important}.align-items-sm-end{align-items:flex-end !important}.align-items-sm-center{align-items:center !important}.align-items-sm-baseline{align-items:baseline !important}.align-items-sm-stretch{align-items:stretch !important}.align-content-sm-start{align-content:flex-start !important}.align-content-sm-end{align-content:flex-end !important}.align-content-sm-center{align-content:center !important}.align-content-sm-between{align-content:space-between !important}.align-content-sm-around{align-content:space-around !important}.align-content-sm-stretch{align-content:stretch !important}.align-self-sm-auto{align-self:auto !important}.align-self-sm-start{align-self:flex-start !important}.align-self-sm-end{align-self:flex-end !important}.align-self-sm-center{align-self:center !important}.align-self-sm-baseline{align-self:baseline !important}.align-self-sm-stretch{align-self:stretch !important}.order-sm-first{order:-1 !important}.order-sm-0{order:0 !important}.order-sm-1{order:1 !important}.order-sm-2{order:2 !important}.order-sm-3{order:3 !important}.order-sm-4{order:4 !important}.order-sm-5{order:5 !important}.order-sm-last{order:6 !important}.m-sm-0{margin:0 !important}.m-sm-1{margin:.25rem !important}.m-sm-2{margin:.5rem !important}.m-sm-3{margin:1rem !important}.m-sm-4{margin:1.5rem !important}.m-sm-5{margin:3rem !important}.m-sm-auto{margin:auto !important}.mx-sm-0{margin-right:0 !important;margin-left:0 !important}.mx-sm-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-sm-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-sm-3{margin-right:1rem !important;margin-left:1rem !important}.mx-sm-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-sm-5{margin-right:3rem !important;margin-left:3rem !important}.mx-sm-auto{margin-right:auto !important;margin-left:auto !important}.my-sm-0{margin-top:0 !important;margin-bottom:0 !important}.my-sm-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-sm-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-sm-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-sm-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-sm-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-sm-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-sm-0{margin-top:0 !important}.mt-sm-1{margin-top:.25rem !important}.mt-sm-2{margin-top:.5rem !important}.mt-sm-3{margin-top:1rem !important}.mt-sm-4{margin-top:1.5rem !important}.mt-sm-5{margin-top:3rem !important}.mt-sm-auto{margin-top:auto !important}.me-sm-0{margin-right:0 !important}.me-sm-1{margin-right:.25rem !important}.me-sm-2{margin-right:.5rem !important}.me-sm-3{margin-right:1rem !important}.me-sm-4{margin-right:1.5rem !important}.me-sm-5{margin-right:3rem !important}.me-sm-auto{margin-right:auto !important}.mb-sm-0{margin-bottom:0 !important}.mb-sm-1{margin-bottom:.25rem !important}.mb-sm-2{margin-bottom:.5rem !important}.mb-sm-3{margin-bottom:1rem !important}.mb-sm-4{margin-bottom:1.5rem !important}.mb-sm-5{margin-bottom:3rem !important}.mb-sm-auto{margin-bottom:auto !important}.ms-sm-0{margin-left:0 !important}.ms-sm-1{margin-left:.25rem !important}.ms-sm-2{margin-left:.5rem !important}.ms-sm-3{margin-left:1rem !important}.ms-sm-4{margin-left:1.5rem !important}.ms-sm-5{margin-left:3rem !important}.ms-sm-auto{margin-left:auto !important}.p-sm-0{padding:0 !important}.p-sm-1{padding:.25rem !important}.p-sm-2{padding:.5rem !important}.p-sm-3{padding:1rem !important}.p-sm-4{padding:1.5rem !important}.p-sm-5{padding:3rem !important}.px-sm-0{padding-right:0 !important;padding-left:0 !important}.px-sm-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-sm-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-sm-3{padding-right:1rem !important;padding-left:1rem !important}.px-sm-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-sm-5{padding-right:3rem !important;padding-left:3rem !important}.py-sm-0{padding-top:0 !important;padding-bottom:0 !important}.py-sm-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-sm-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-sm-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-sm-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-sm-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-sm-0{padding-top:0 !important}.pt-sm-1{padding-top:.25rem !important}.pt-sm-2{padding-top:.5rem !important}.pt-sm-3{padding-top:1rem !important}.pt-sm-4{padding-top:1.5rem !important}.pt-sm-5{padding-top:3rem !important}.pe-sm-0{padding-right:0 !important}.pe-sm-1{padding-right:.25rem !important}.pe-sm-2{padding-right:.5rem !important}.pe-sm-3{padding-right:1rem !important}.pe-sm-4{padding-right:1.5rem !important}.pe-sm-5{padding-right:3rem !important}.pb-sm-0{padding-bottom:0 !important}.pb-sm-1{padding-bottom:.25rem !important}.pb-sm-2{padding-bottom:.5rem !important}.pb-sm-3{padding-bottom:1rem !important}.pb-sm-4{padding-bottom:1.5rem !important}.pb-sm-5{padding-bottom:3rem !important}.ps-sm-0{padding-left:0 !important}.ps-sm-1{padding-left:.25rem !important}.ps-sm-2{padding-left:.5rem !important}.ps-sm-3{padding-left:1rem !important}.ps-sm-4{padding-left:1.5rem !important}.ps-sm-5{padding-left:3rem !important}.text-sm-start{text-align:left !important}.text-sm-end{text-align:right !important}.text-sm-center{text-align:center !important}}@media(min-width: 768px){.float-md-start{float:left !important}.float-md-end{float:right !important}.float-md-none{float:none !important}.d-md-inline{display:inline !important}.d-md-inline-block{display:inline-block !important}.d-md-block{display:block !important}.d-md-grid{display:grid !important}.d-md-table{display:table !important}.d-md-table-row{display:table-row !important}.d-md-table-cell{display:table-cell !important}.d-md-flex{display:flex !important}.d-md-inline-flex{display:inline-flex !important}.d-md-none{display:none !important}.flex-md-fill{flex:1 1 auto !important}.flex-md-row{flex-direction:row !important}.flex-md-column{flex-direction:column !important}.flex-md-row-reverse{flex-direction:row-reverse !important}.flex-md-column-reverse{flex-direction:column-reverse !important}.flex-md-grow-0{flex-grow:0 !important}.flex-md-grow-1{flex-grow:1 !important}.flex-md-shrink-0{flex-shrink:0 !important}.flex-md-shrink-1{flex-shrink:1 !important}.flex-md-wrap{flex-wrap:wrap !important}.flex-md-nowrap{flex-wrap:nowrap !important}.flex-md-wrap-reverse{flex-wrap:wrap-reverse !important}.gap-md-0{gap:0 !important}.gap-md-1{gap:.25rem !important}.gap-md-2{gap:.5rem !important}.gap-md-3{gap:1rem !important}.gap-md-4{gap:1.5rem !important}.gap-md-5{gap:3rem !important}.justify-content-md-start{justify-content:flex-start !important}.justify-content-md-end{justify-content:flex-end !important}.justify-content-md-center{justify-content:center !important}.justify-content-md-between{justify-content:space-between !important}.justify-content-md-around{justify-content:space-around !important}.justify-content-md-evenly{justify-content:space-evenly !important}.align-items-md-start{align-items:flex-start !important}.align-items-md-end{align-items:flex-end !important}.align-items-md-center{align-items:center !important}.align-items-md-baseline{align-items:baseline !important}.align-items-md-stretch{align-items:stretch !important}.align-content-md-start{align-content:flex-start !important}.align-content-md-end{align-content:flex-end !important}.align-content-md-center{align-content:center !important}.align-content-md-between{align-content:space-between !important}.align-content-md-around{align-content:space-around !important}.align-content-md-stretch{align-content:stretch !important}.align-self-md-auto{align-self:auto !important}.align-self-md-start{align-self:flex-start !important}.align-self-md-end{align-self:flex-end !important}.align-self-md-center{align-self:center !important}.align-self-md-baseline{align-self:baseline !important}.align-self-md-stretch{align-self:stretch !important}.order-md-first{order:-1 !important}.order-md-0{order:0 !important}.order-md-1{order:1 !important}.order-md-2{order:2 !important}.order-md-3{order:3 !important}.order-md-4{order:4 !important}.order-md-5{order:5 !important}.order-md-last{order:6 !important}.m-md-0{margin:0 !important}.m-md-1{margin:.25rem !important}.m-md-2{margin:.5rem !important}.m-md-3{margin:1rem !important}.m-md-4{margin:1.5rem !important}.m-md-5{margin:3rem !important}.m-md-auto{margin:auto !important}.mx-md-0{margin-right:0 !important;margin-left:0 !important}.mx-md-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-md-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-md-3{margin-right:1rem !important;margin-left:1rem !important}.mx-md-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-md-5{margin-right:3rem !important;margin-left:3rem !important}.mx-md-auto{margin-right:auto !important;margin-left:auto !important}.my-md-0{margin-top:0 !important;margin-bottom:0 !important}.my-md-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-md-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-md-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-md-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-md-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-md-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-md-0{margin-top:0 !important}.mt-md-1{margin-top:.25rem !important}.mt-md-2{margin-top:.5rem !important}.mt-md-3{margin-top:1rem !important}.mt-md-4{margin-top:1.5rem !important}.mt-md-5{margin-top:3rem !important}.mt-md-auto{margin-top:auto !important}.me-md-0{margin-right:0 !important}.me-md-1{margin-right:.25rem !important}.me-md-2{margin-right:.5rem !important}.me-md-3{margin-right:1rem !important}.me-md-4{margin-right:1.5rem !important}.me-md-5{margin-right:3rem !important}.me-md-auto{margin-right:auto !important}.mb-md-0{margin-bottom:0 !important}.mb-md-1{margin-bottom:.25rem !important}.mb-md-2{margin-bottom:.5rem !important}.mb-md-3{margin-bottom:1rem !important}.mb-md-4{margin-bottom:1.5rem !important}.mb-md-5{margin-bottom:3rem !important}.mb-md-auto{margin-bottom:auto !important}.ms-md-0{margin-left:0 !important}.ms-md-1{margin-left:.25rem !important}.ms-md-2{margin-left:.5rem !important}.ms-md-3{margin-left:1rem !important}.ms-md-4{margin-left:1.5rem !important}.ms-md-5{margin-left:3rem !important}.ms-md-auto{margin-left:auto !important}.p-md-0{padding:0 !important}.p-md-1{padding:.25rem !important}.p-md-2{padding:.5rem !important}.p-md-3{padding:1rem !important}.p-md-4{padding:1.5rem !important}.p-md-5{padding:3rem !important}.px-md-0{padding-right:0 !important;padding-left:0 !important}.px-md-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-md-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-md-3{padding-right:1rem !important;padding-left:1rem !important}.px-md-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-md-5{padding-right:3rem !important;padding-left:3rem !important}.py-md-0{padding-top:0 !important;padding-bottom:0 !important}.py-md-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-md-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-md-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-md-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-md-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-md-0{padding-top:0 !important}.pt-md-1{padding-top:.25rem !important}.pt-md-2{padding-top:.5rem !important}.pt-md-3{padding-top:1rem !important}.pt-md-4{padding-top:1.5rem !important}.pt-md-5{padding-top:3rem !important}.pe-md-0{padding-right:0 !important}.pe-md-1{padding-right:.25rem !important}.pe-md-2{padding-right:.5rem !important}.pe-md-3{padding-right:1rem !important}.pe-md-4{padding-right:1.5rem !important}.pe-md-5{padding-right:3rem !important}.pb-md-0{padding-bottom:0 !important}.pb-md-1{padding-bottom:.25rem !important}.pb-md-2{padding-bottom:.5rem !important}.pb-md-3{padding-bottom:1rem !important}.pb-md-4{padding-bottom:1.5rem !important}.pb-md-5{padding-bottom:3rem !important}.ps-md-0{padding-left:0 !important}.ps-md-1{padding-left:.25rem !important}.ps-md-2{padding-left:.5rem !important}.ps-md-3{padding-left:1rem !important}.ps-md-4{padding-left:1.5rem !important}.ps-md-5{padding-left:3rem !important}.text-md-start{text-align:left !important}.text-md-end{text-align:right !important}.text-md-center{text-align:center !important}}@media(min-width: 992px){.float-lg-start{float:left !important}.float-lg-end{float:right !important}.float-lg-none{float:none !important}.d-lg-inline{display:inline !important}.d-lg-inline-block{display:inline-block !important}.d-lg-block{display:block !important}.d-lg-grid{display:grid !important}.d-lg-table{display:table !important}.d-lg-table-row{display:table-row !important}.d-lg-table-cell{display:table-cell !important}.d-lg-flex{display:flex !important}.d-lg-inline-flex{display:inline-flex !important}.d-lg-none{display:none !important}.flex-lg-fill{flex:1 1 auto !important}.flex-lg-row{flex-direction:row !important}.flex-lg-column{flex-direction:column !important}.flex-lg-row-reverse{flex-direction:row-reverse !important}.flex-lg-column-reverse{flex-direction:column-reverse !important}.flex-lg-grow-0{flex-grow:0 !important}.flex-lg-grow-1{flex-grow:1 !important}.flex-lg-shrink-0{flex-shrink:0 !important}.flex-lg-shrink-1{flex-shrink:1 !important}.flex-lg-wrap{flex-wrap:wrap !important}.flex-lg-nowrap{flex-wrap:nowrap !important}.flex-lg-wrap-reverse{flex-wrap:wrap-reverse !important}.gap-lg-0{gap:0 !important}.gap-lg-1{gap:.25rem !important}.gap-lg-2{gap:.5rem !important}.gap-lg-3{gap:1rem !important}.gap-lg-4{gap:1.5rem !important}.gap-lg-5{gap:3rem !important}.justify-content-lg-start{justify-content:flex-start !important}.justify-content-lg-end{justify-content:flex-end !important}.justify-content-lg-center{justify-content:center !important}.justify-content-lg-between{justify-content:space-between !important}.justify-content-lg-around{justify-content:space-around !important}.justify-content-lg-evenly{justify-content:space-evenly !important}.align-items-lg-start{align-items:flex-start !important}.align-items-lg-end{align-items:flex-end !important}.align-items-lg-center{align-items:center !important}.align-items-lg-baseline{align-items:baseline !important}.align-items-lg-stretch{align-items:stretch !important}.align-content-lg-start{align-content:flex-start !important}.align-content-lg-end{align-content:flex-end !important}.align-content-lg-center{align-content:center !important}.align-content-lg-between{align-content:space-between !important}.align-content-lg-around{align-content:space-around !important}.align-content-lg-stretch{align-content:stretch !important}.align-self-lg-auto{align-self:auto !important}.align-self-lg-start{align-self:flex-start !important}.align-self-lg-end{align-self:flex-end !important}.align-self-lg-center{align-self:center !important}.align-self-lg-baseline{align-self:baseline !important}.align-self-lg-stretch{align-self:stretch !important}.order-lg-first{order:-1 !important}.order-lg-0{order:0 !important}.order-lg-1{order:1 !important}.order-lg-2{order:2 !important}.order-lg-3{order:3 !important}.order-lg-4{order:4 !important}.order-lg-5{order:5 !important}.order-lg-last{order:6 !important}.m-lg-0{margin:0 !important}.m-lg-1{margin:.25rem !important}.m-lg-2{margin:.5rem !important}.m-lg-3{margin:1rem !important}.m-lg-4{margin:1.5rem !important}.m-lg-5{margin:3rem !important}.m-lg-auto{margin:auto !important}.mx-lg-0{margin-right:0 !important;margin-left:0 !important}.mx-lg-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-lg-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-lg-3{margin-right:1rem !important;margin-left:1rem !important}.mx-lg-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-lg-5{margin-right:3rem !important;margin-left:3rem !important}.mx-lg-auto{margin-right:auto !important;margin-left:auto !important}.my-lg-0{margin-top:0 !important;margin-bottom:0 !important}.my-lg-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-lg-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-lg-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-lg-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-lg-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-lg-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-lg-0{margin-top:0 !important}.mt-lg-1{margin-top:.25rem !important}.mt-lg-2{margin-top:.5rem !important}.mt-lg-3{margin-top:1rem !important}.mt-lg-4{margin-top:1.5rem !important}.mt-lg-5{margin-top:3rem !important}.mt-lg-auto{margin-top:auto !important}.me-lg-0{margin-right:0 !important}.me-lg-1{margin-right:.25rem !important}.me-lg-2{margin-right:.5rem !important}.me-lg-3{margin-right:1rem !important}.me-lg-4{margin-right:1.5rem !important}.me-lg-5{margin-right:3rem !important}.me-lg-auto{margin-right:auto !important}.mb-lg-0{margin-bottom:0 !important}.mb-lg-1{margin-bottom:.25rem !important}.mb-lg-2{margin-bottom:.5rem !important}.mb-lg-3{margin-bottom:1rem !important}.mb-lg-4{margin-bottom:1.5rem !important}.mb-lg-5{margin-bottom:3rem !important}.mb-lg-auto{margin-bottom:auto !important}.ms-lg-0{margin-left:0 !important}.ms-lg-1{margin-left:.25rem !important}.ms-lg-2{margin-left:.5rem !important}.ms-lg-3{margin-left:1rem !important}.ms-lg-4{margin-left:1.5rem !important}.ms-lg-5{margin-left:3rem !important}.ms-lg-auto{margin-left:auto !important}.p-lg-0{padding:0 !important}.p-lg-1{padding:.25rem !important}.p-lg-2{padding:.5rem !important}.p-lg-3{padding:1rem !important}.p-lg-4{padding:1.5rem !important}.p-lg-5{padding:3rem !important}.px-lg-0{padding-right:0 !important;padding-left:0 !important}.px-lg-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-lg-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-lg-3{padding-right:1rem !important;padding-left:1rem !important}.px-lg-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-lg-5{padding-right:3rem !important;padding-left:3rem !important}.py-lg-0{padding-top:0 !important;padding-bottom:0 !important}.py-lg-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-lg-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-lg-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-lg-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-lg-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-lg-0{padding-top:0 !important}.pt-lg-1{padding-top:.25rem !important}.pt-lg-2{padding-top:.5rem !important}.pt-lg-3{padding-top:1rem !important}.pt-lg-4{padding-top:1.5rem !important}.pt-lg-5{padding-top:3rem !important}.pe-lg-0{padding-right:0 !important}.pe-lg-1{padding-right:.25rem !important}.pe-lg-2{padding-right:.5rem !important}.pe-lg-3{padding-right:1rem !important}.pe-lg-4{padding-right:1.5rem !important}.pe-lg-5{padding-right:3rem !important}.pb-lg-0{padding-bottom:0 !important}.pb-lg-1{padding-bottom:.25rem !important}.pb-lg-2{padding-bottom:.5rem !important}.pb-lg-3{padding-bottom:1rem !important}.pb-lg-4{padding-bottom:1.5rem !important}.pb-lg-5{padding-bottom:3rem !important}.ps-lg-0{padding-left:0 !important}.ps-lg-1{padding-left:.25rem !important}.ps-lg-2{padding-left:.5rem !important}.ps-lg-3{padding-left:1rem !important}.ps-lg-4{padding-left:1.5rem !important}.ps-lg-5{padding-left:3rem !important}.text-lg-start{text-align:left !important}.text-lg-end{text-align:right !important}.text-lg-center{text-align:center !important}}@media(min-width: 1200px){.float-xl-start{float:left !important}.float-xl-end{float:right !important}.float-xl-none{float:none !important}.d-xl-inline{display:inline !important}.d-xl-inline-block{display:inline-block !important}.d-xl-block{display:block !important}.d-xl-grid{display:grid !important}.d-xl-table{display:table !important}.d-xl-table-row{display:table-row !important}.d-xl-table-cell{display:table-cell !important}.d-xl-flex{display:flex !important}.d-xl-inline-flex{display:inline-flex !important}.d-xl-none{display:none !important}.flex-xl-fill{flex:1 1 auto !important}.flex-xl-row{flex-direction:row !important}.flex-xl-column{flex-direction:column !important}.flex-xl-row-reverse{flex-direction:row-reverse !important}.flex-xl-column-reverse{flex-direction:column-reverse !important}.flex-xl-grow-0{flex-grow:0 !important}.flex-xl-grow-1{flex-grow:1 !important}.flex-xl-shrink-0{flex-shrink:0 !important}.flex-xl-shrink-1{flex-shrink:1 !important}.flex-xl-wrap{flex-wrap:wrap !important}.flex-xl-nowrap{flex-wrap:nowrap !important}.flex-xl-wrap-reverse{flex-wrap:wrap-reverse !important}.gap-xl-0{gap:0 !important}.gap-xl-1{gap:.25rem !important}.gap-xl-2{gap:.5rem !important}.gap-xl-3{gap:1rem !important}.gap-xl-4{gap:1.5rem !important}.gap-xl-5{gap:3rem !important}.justify-content-xl-start{justify-content:flex-start !important}.justify-content-xl-end{justify-content:flex-end !important}.justify-content-xl-center{justify-content:center !important}.justify-content-xl-between{justify-content:space-between !important}.justify-content-xl-around{justify-content:space-around !important}.justify-content-xl-evenly{justify-content:space-evenly !important}.align-items-xl-start{align-items:flex-start !important}.align-items-xl-end{align-items:flex-end !important}.align-items-xl-center{align-items:center !important}.align-items-xl-baseline{align-items:baseline !important}.align-items-xl-stretch{align-items:stretch !important}.align-content-xl-start{align-content:flex-start !important}.align-content-xl-end{align-content:flex-end !important}.align-content-xl-center{align-content:center !important}.align-content-xl-between{align-content:space-between !important}.align-content-xl-around{align-content:space-around !important}.align-content-xl-stretch{align-content:stretch !important}.align-self-xl-auto{align-self:auto !important}.align-self-xl-start{align-self:flex-start !important}.align-self-xl-end{align-self:flex-end !important}.align-self-xl-center{align-self:center !important}.align-self-xl-baseline{align-self:baseline !important}.align-self-xl-stretch{align-self:stretch !important}.order-xl-first{order:-1 !important}.order-xl-0{order:0 !important}.order-xl-1{order:1 !important}.order-xl-2{order:2 !important}.order-xl-3{order:3 !important}.order-xl-4{order:4 !important}.order-xl-5{order:5 !important}.order-xl-last{order:6 !important}.m-xl-0{margin:0 !important}.m-xl-1{margin:.25rem !important}.m-xl-2{margin:.5rem !important}.m-xl-3{margin:1rem !important}.m-xl-4{margin:1.5rem !important}.m-xl-5{margin:3rem !important}.m-xl-auto{margin:auto !important}.mx-xl-0{margin-right:0 !important;margin-left:0 !important}.mx-xl-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-xl-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-xl-3{margin-right:1rem !important;margin-left:1rem !important}.mx-xl-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-xl-5{margin-right:3rem !important;margin-left:3rem !important}.mx-xl-auto{margin-right:auto !important;margin-left:auto !important}.my-xl-0{margin-top:0 !important;margin-bottom:0 !important}.my-xl-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-xl-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-xl-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-xl-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-xl-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-xl-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-xl-0{margin-top:0 !important}.mt-xl-1{margin-top:.25rem !important}.mt-xl-2{margin-top:.5rem !important}.mt-xl-3{margin-top:1rem !important}.mt-xl-4{margin-top:1.5rem !important}.mt-xl-5{margin-top:3rem !important}.mt-xl-auto{margin-top:auto !important}.me-xl-0{margin-right:0 !important}.me-xl-1{margin-right:.25rem !important}.me-xl-2{margin-right:.5rem !important}.me-xl-3{margin-right:1rem !important}.me-xl-4{margin-right:1.5rem !important}.me-xl-5{margin-right:3rem !important}.me-xl-auto{margin-right:auto !important}.mb-xl-0{margin-bottom:0 !important}.mb-xl-1{margin-bottom:.25rem !important}.mb-xl-2{margin-bottom:.5rem !important}.mb-xl-3{margin-bottom:1rem !important}.mb-xl-4{margin-bottom:1.5rem !important}.mb-xl-5{margin-bottom:3rem !important}.mb-xl-auto{margin-bottom:auto !important}.ms-xl-0{margin-left:0 !important}.ms-xl-1{margin-left:.25rem !important}.ms-xl-2{margin-left:.5rem !important}.ms-xl-3{margin-left:1rem !important}.ms-xl-4{margin-left:1.5rem !important}.ms-xl-5{margin-left:3rem !important}.ms-xl-auto{margin-left:auto !important}.p-xl-0{padding:0 !important}.p-xl-1{padding:.25rem !important}.p-xl-2{padding:.5rem !important}.p-xl-3{padding:1rem !important}.p-xl-4{padding:1.5rem !important}.p-xl-5{padding:3rem !important}.px-xl-0{padding-right:0 !important;padding-left:0 !important}.px-xl-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-xl-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-xl-3{padding-right:1rem !important;padding-left:1rem !important}.px-xl-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-xl-5{padding-right:3rem !important;padding-left:3rem !important}.py-xl-0{padding-top:0 !important;padding-bottom:0 !important}.py-xl-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-xl-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-xl-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-xl-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-xl-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-xl-0{padding-top:0 !important}.pt-xl-1{padding-top:.25rem !important}.pt-xl-2{padding-top:.5rem !important}.pt-xl-3{padding-top:1rem !important}.pt-xl-4{padding-top:1.5rem !important}.pt-xl-5{padding-top:3rem !important}.pe-xl-0{padding-right:0 !important}.pe-xl-1{padding-right:.25rem !important}.pe-xl-2{padding-right:.5rem !important}.pe-xl-3{padding-right:1rem !important}.pe-xl-4{padding-right:1.5rem !important}.pe-xl-5{padding-right:3rem !important}.pb-xl-0{padding-bottom:0 !important}.pb-xl-1{padding-bottom:.25rem !important}.pb-xl-2{padding-bottom:.5rem !important}.pb-xl-3{padding-bottom:1rem !important}.pb-xl-4{padding-bottom:1.5rem !important}.pb-xl-5{padding-bottom:3rem !important}.ps-xl-0{padding-left:0 !important}.ps-xl-1{padding-left:.25rem !important}.ps-xl-2{padding-left:.5rem !important}.ps-xl-3{padding-left:1rem !important}.ps-xl-4{padding-left:1.5rem !important}.ps-xl-5{padding-left:3rem !important}.text-xl-start{text-align:left !important}.text-xl-end{text-align:right !important}.text-xl-center{text-align:center !important}}@media(min-width: 1400px){.float-xxl-start{float:left !important}.float-xxl-end{float:right !important}.float-xxl-none{float:none !important}.d-xxl-inline{display:inline !important}.d-xxl-inline-block{display:inline-block !important}.d-xxl-block{display:block !important}.d-xxl-grid{display:grid !important}.d-xxl-table{display:table !important}.d-xxl-table-row{display:table-row !important}.d-xxl-table-cell{display:table-cell !important}.d-xxl-flex{display:flex !important}.d-xxl-inline-flex{display:inline-flex !important}.d-xxl-none{display:none !important}.flex-xxl-fill{flex:1 1 auto !important}.flex-xxl-row{flex-direction:row !important}.flex-xxl-column{flex-direction:column !important}.flex-xxl-row-reverse{flex-direction:row-reverse !important}.flex-xxl-column-reverse{flex-direction:column-reverse !important}.flex-xxl-grow-0{flex-grow:0 !important}.flex-xxl-grow-1{flex-grow:1 !important}.flex-xxl-shrink-0{flex-shrink:0 !important}.flex-xxl-shrink-1{flex-shrink:1 !important}.flex-xxl-wrap{flex-wrap:wrap !important}.flex-xxl-nowrap{flex-wrap:nowrap !important}.flex-xxl-wrap-reverse{flex-wrap:wrap-reverse !important}.gap-xxl-0{gap:0 !important}.gap-xxl-1{gap:.25rem !important}.gap-xxl-2{gap:.5rem !important}.gap-xxl-3{gap:1rem !important}.gap-xxl-4{gap:1.5rem !important}.gap-xxl-5{gap:3rem !important}.justify-content-xxl-start{justify-content:flex-start !important}.justify-content-xxl-end{justify-content:flex-end !important}.justify-content-xxl-center{justify-content:center !important}.justify-content-xxl-between{justify-content:space-between !important}.justify-content-xxl-around{justify-content:space-around !important}.justify-content-xxl-evenly{justify-content:space-evenly !important}.align-items-xxl-start{align-items:flex-start !important}.align-items-xxl-end{align-items:flex-end !important}.align-items-xxl-center{align-items:center !important}.align-items-xxl-baseline{align-items:baseline !important}.align-items-xxl-stretch{align-items:stretch !important}.align-content-xxl-start{align-content:flex-start !important}.align-content-xxl-end{align-content:flex-end !important}.align-content-xxl-center{align-content:center !important}.align-content-xxl-between{align-content:space-between !important}.align-content-xxl-around{align-content:space-around !important}.align-content-xxl-stretch{align-content:stretch !important}.align-self-xxl-auto{align-self:auto !important}.align-self-xxl-start{align-self:flex-start !important}.align-self-xxl-end{align-self:flex-end !important}.align-self-xxl-center{align-self:center !important}.align-self-xxl-baseline{align-self:baseline !important}.align-self-xxl-stretch{align-self:stretch !important}.order-xxl-first{order:-1 !important}.order-xxl-0{order:0 !important}.order-xxl-1{order:1 !important}.order-xxl-2{order:2 !important}.order-xxl-3{order:3 !important}.order-xxl-4{order:4 !important}.order-xxl-5{order:5 !important}.order-xxl-last{order:6 !important}.m-xxl-0{margin:0 !important}.m-xxl-1{margin:.25rem !important}.m-xxl-2{margin:.5rem !important}.m-xxl-3{margin:1rem !important}.m-xxl-4{margin:1.5rem !important}.m-xxl-5{margin:3rem !important}.m-xxl-auto{margin:auto !important}.mx-xxl-0{margin-right:0 !important;margin-left:0 !important}.mx-xxl-1{margin-right:.25rem !important;margin-left:.25rem !important}.mx-xxl-2{margin-right:.5rem !important;margin-left:.5rem !important}.mx-xxl-3{margin-right:1rem !important;margin-left:1rem !important}.mx-xxl-4{margin-right:1.5rem !important;margin-left:1.5rem !important}.mx-xxl-5{margin-right:3rem !important;margin-left:3rem !important}.mx-xxl-auto{margin-right:auto !important;margin-left:auto !important}.my-xxl-0{margin-top:0 !important;margin-bottom:0 !important}.my-xxl-1{margin-top:.25rem !important;margin-bottom:.25rem !important}.my-xxl-2{margin-top:.5rem !important;margin-bottom:.5rem !important}.my-xxl-3{margin-top:1rem !important;margin-bottom:1rem !important}.my-xxl-4{margin-top:1.5rem !important;margin-bottom:1.5rem !important}.my-xxl-5{margin-top:3rem !important;margin-bottom:3rem !important}.my-xxl-auto{margin-top:auto !important;margin-bottom:auto !important}.mt-xxl-0{margin-top:0 !important}.mt-xxl-1{margin-top:.25rem !important}.mt-xxl-2{margin-top:.5rem !important}.mt-xxl-3{margin-top:1rem !important}.mt-xxl-4{margin-top:1.5rem !important}.mt-xxl-5{margin-top:3rem !important}.mt-xxl-auto{margin-top:auto !important}.me-xxl-0{margin-right:0 !important}.me-xxl-1{margin-right:.25rem !important}.me-xxl-2{margin-right:.5rem !important}.me-xxl-3{margin-right:1rem !important}.me-xxl-4{margin-right:1.5rem !important}.me-xxl-5{margin-right:3rem !important}.me-xxl-auto{margin-right:auto !important}.mb-xxl-0{margin-bottom:0 !important}.mb-xxl-1{margin-bottom:.25rem !important}.mb-xxl-2{margin-bottom:.5rem !important}.mb-xxl-3{margin-bottom:1rem !important}.mb-xxl-4{margin-bottom:1.5rem !important}.mb-xxl-5{margin-bottom:3rem !important}.mb-xxl-auto{margin-bottom:auto !important}.ms-xxl-0{margin-left:0 !important}.ms-xxl-1{margin-left:.25rem !important}.ms-xxl-2{margin-left:.5rem !important}.ms-xxl-3{margin-left:1rem !important}.ms-xxl-4{margin-left:1.5rem !important}.ms-xxl-5{margin-left:3rem !important}.ms-xxl-auto{margin-left:auto !important}.p-xxl-0{padding:0 !important}.p-xxl-1{padding:.25rem !important}.p-xxl-2{padding:.5rem !important}.p-xxl-3{padding:1rem !important}.p-xxl-4{padding:1.5rem !important}.p-xxl-5{padding:3rem !important}.px-xxl-0{padding-right:0 !important;padding-left:0 !important}.px-xxl-1{padding-right:.25rem !important;padding-left:.25rem !important}.px-xxl-2{padding-right:.5rem !important;padding-left:.5rem !important}.px-xxl-3{padding-right:1rem !important;padding-left:1rem !important}.px-xxl-4{padding-right:1.5rem !important;padding-left:1.5rem !important}.px-xxl-5{padding-right:3rem !important;padding-left:3rem !important}.py-xxl-0{padding-top:0 !important;padding-bottom:0 !important}.py-xxl-1{padding-top:.25rem !important;padding-bottom:.25rem !important}.py-xxl-2{padding-top:.5rem !important;padding-bottom:.5rem !important}.py-xxl-3{padding-top:1rem !important;padding-bottom:1rem !important}.py-xxl-4{padding-top:1.5rem !important;padding-bottom:1.5rem !important}.py-xxl-5{padding-top:3rem !important;padding-bottom:3rem !important}.pt-xxl-0{padding-top:0 !important}.pt-xxl-1{padding-top:.25rem !important}.pt-xxl-2{padding-top:.5rem !important}.pt-xxl-3{padding-top:1rem !important}.pt-xxl-4{padding-top:1.5rem !important}.pt-xxl-5{padding-top:3rem !important}.pe-xxl-0{padding-right:0 !important}.pe-xxl-1{padding-right:.25rem !important}.pe-xxl-2{padding-right:.5rem !important}.pe-xxl-3{padding-right:1rem !important}.pe-xxl-4{padding-right:1.5rem !important}.pe-xxl-5{padding-right:3rem !important}.pb-xxl-0{padding-bottom:0 !important}.pb-xxl-1{padding-bottom:.25rem !important}.pb-xxl-2{padding-bottom:.5rem !important}.pb-xxl-3{padding-bottom:1rem !important}.pb-xxl-4{padding-bottom:1.5rem !important}.pb-xxl-5{padding-bottom:3rem !important}.ps-xxl-0{padding-left:0 !important}.ps-xxl-1{padding-left:.25rem !important}.ps-xxl-2{padding-left:.5rem !important}.ps-xxl-3{padding-left:1rem !important}.ps-xxl-4{padding-left:1.5rem !important}.ps-xxl-5{padding-left:3rem !important}.text-xxl-start{text-align:left !important}.text-xxl-end{text-align:right !important}.text-xxl-center{text-align:center !important}}.bg-default{color:#fff}.bg-primary{color:#fff}.bg-secondary{color:#fff}.bg-success{color:#fff}.bg-info{color:#fff}.bg-warning{color:#fff}.bg-danger{color:#fff}.bg-light{color:#000}.bg-dark{color:#fff}@media(min-width: 1200px){.fs-1{font-size:2rem !important}.fs-2{font-size:1.65rem !important}.fs-3{font-size:1.45rem !important}}@media print{.d-print-inline{display:inline !important}.d-print-inline-block{display:inline-block !important}.d-print-block{display:block !important}.d-print-grid{display:grid !important}.d-print-table{display:table !important}.d-print-table-row{display:table-row !important}.d-print-table-cell{display:table-cell !important}.d-print-flex{display:flex !important}.d-print-inline-flex{display:inline-flex !important}.d-print-none{display:none !important}}.quarto-container{min-height:calc(100vh - 132px)}footer.footer .nav-footer,#quarto-header>nav{padding-left:1em;padding-right:1em}nav[role=doc-toc]{padding-left:.5em}#quarto-content>*{padding-top:14px}@media(max-width: 991.98px){#quarto-content>*{padding-top:0}#quarto-content .subtitle{padding-top:14px}#quarto-content section:first-of-type h2:first-of-type,#quarto-content section:first-of-type .h2:first-of-type{margin-top:1rem}}.headroom-target,header.headroom{will-change:transform;transition:position 200ms linear;transition:all 200ms linear}header.headroom--pinned{transform:translateY(0%)}header.headroom--unpinned{transform:translateY(-100%)}.navbar-container{width:100%}.navbar-brand{overflow:hidden;text-overflow:ellipsis}.navbar-brand-container{max-width:calc(100% - 115px);min-width:0;display:flex;align-items:center}@media(min-width: 992px){.navbar-brand-container{margin-right:1em}}.navbar-brand.navbar-brand-logo{margin-right:4px;display:inline-flex}.navbar-toggler{flex-basis:content;flex-shrink:0}.navbar .navbar-toggler{order:-1;margin-right:.5em}.navbar-logo{max-height:24px;width:auto;padding-right:4px}nav .nav-item:not(.compact){padding-top:1px}nav .nav-link i,nav .dropdown-item i{padding-right:1px}.navbar-expand-lg .navbar-nav .nav-link{padding-left:.6rem;padding-right:.6rem}nav .nav-item.compact .nav-link{padding-left:.5rem;padding-right:.5rem;font-size:1.1rem}.navbar .quarto-navbar-tools div.dropdown{display:inline-block}.navbar .quarto-navbar-tools .quarto-navigation-tool{color:#fdfeff}.navbar .quarto-navbar-tools .quarto-navigation-tool:hover{color:#fdfeff}@media(max-width: 991.98px){.navbar .quarto-navbar-tools{margin-top:.25em;padding-top:.75em;display:block;color:solid #007ffd 1px;text-align:center;vertical-align:middle;margin-right:auto}}.navbar-nav .dropdown-menu{min-width:220px;font-size:.9rem}.navbar .navbar-nav .nav-link.dropdown-toggle::after{opacity:.75;vertical-align:.175em}.navbar ul.dropdown-menu{padding-top:0;padding-bottom:0}.navbar .dropdown-header{text-transform:uppercase;font-size:.8rem;padding:0 .5rem}.navbar .dropdown-item{padding:.4rem .5rem}.navbar .dropdown-item>i.bi{margin-left:.1rem;margin-right:.25em}.sidebar #quarto-search{margin-top:-1px}.sidebar #quarto-search svg.aa-SubmitIcon{width:16px;height:16px}.sidebar-navigation a{color:inherit}.sidebar-title{margin-top:.25rem;padding-bottom:.5rem;font-size:1.3rem;line-height:1.6rem;visibility:visible}.sidebar-title>a{font-size:inherit;text-decoration:none}.sidebar-title .sidebar-tools-main{margin-top:-6px}@media(max-width: 991.98px){#quarto-sidebar div.sidebar-header{padding-top:.2em}}.sidebar-header-stacked .sidebar-title{margin-top:.6rem}.sidebar-logo{max-width:90%;padding-bottom:.5rem}.sidebar-logo-link{text-decoration:none}.sidebar-navigation li a{text-decoration:none}.sidebar-navigation .quarto-navigation-tool{opacity:.7;font-size:.875rem}#quarto-sidebar>nav>.sidebar-tools-main{margin-left:14px}.sidebar-tools-main{display:inline-flex;margin-left:0px;order:2}.sidebar-tools-main:not(.tools-wide){vertical-align:middle}.sidebar-navigation .quarto-navigation-tool.dropdown-toggle::after{display:none}.sidebar.sidebar-navigation>*{padding-top:1em}.sidebar-item{margin-bottom:.2em}.sidebar-section{margin-top:.2em;padding-left:.5em;padding-bottom:.2em}.sidebar-item .sidebar-item-container{display:flex;justify-content:space-between}.sidebar-item-toggle:hover{cursor:pointer}.sidebar-item .sidebar-item-toggle .bi{font-size:.7rem;text-align:center}.sidebar-item .sidebar-item-toggle .bi-chevron-right::before{transition:transform 200ms ease}.sidebar-item .sidebar-item-toggle[aria-expanded=false] .bi-chevron-right::before{transform:none}.sidebar-item .sidebar-item-toggle[aria-expanded=true] .bi-chevron-right::before{transform:rotate(90deg)}.sidebar-navigation .sidebar-divider{margin-left:0;margin-right:0;margin-top:.5rem;margin-bottom:.5rem}@media(max-width: 991.98px){.quarto-secondary-nav{display:block}.quarto-secondary-nav button.quarto-search-button{padding-right:0em;padding-left:2em}.quarto-secondary-nav button.quarto-btn-toggle{margin-left:-0.75rem;margin-right:.15rem}.quarto-secondary-nav nav.quarto-page-breadcrumbs{display:flex;align-items:center;padding-right:1em;margin-left:-0.25em}.quarto-secondary-nav nav.quarto-page-breadcrumbs a{text-decoration:none}.quarto-secondary-nav nav.quarto-page-breadcrumbs ol.breadcrumb{margin-bottom:0}}@media(min-width: 992px){.quarto-secondary-nav{display:none}}.quarto-secondary-nav .quarto-btn-toggle{color:#595959}.quarto-secondary-nav[aria-expanded=false] .quarto-btn-toggle .bi-chevron-right::before{transform:none}.quarto-secondary-nav[aria-expanded=true] .quarto-btn-toggle .bi-chevron-right::before{transform:rotate(90deg)}.quarto-secondary-nav .quarto-btn-toggle .bi-chevron-right::before{transition:transform 200ms ease}.quarto-secondary-nav{cursor:pointer}.quarto-secondary-nav-title{margin-top:.3em;color:#595959;padding-top:4px}.quarto-secondary-nav nav.quarto-page-breadcrumbs{color:#595959}.quarto-secondary-nav nav.quarto-page-breadcrumbs a{color:#595959}.quarto-secondary-nav nav.quarto-page-breadcrumbs a:hover{color:rgba(27,88,157,.8)}.quarto-secondary-nav nav.quarto-page-breadcrumbs .breadcrumb-item::before{color:#8c8c8c}div.sidebar-item-container{color:#595959}div.sidebar-item-container:hover,div.sidebar-item-container:focus{color:rgba(27,88,157,.8)}div.sidebar-item-container.disabled{color:rgba(89,89,89,.75)}div.sidebar-item-container .active,div.sidebar-item-container .show>.nav-link,div.sidebar-item-container .sidebar-link>code{color:#1b589d}div.sidebar.sidebar-navigation.rollup.quarto-sidebar-toggle-contents,nav.sidebar.sidebar-navigation:not(.rollup){background-color:#fff}@media(max-width: 991.98px){.sidebar-navigation .sidebar-item a,.nav-page .nav-page-text,.sidebar-navigation{font-size:1rem}.sidebar-navigation ul.sidebar-section.depth1 .sidebar-section-item{font-size:1.1rem}.sidebar-logo{display:none}.sidebar.sidebar-navigation{position:static;border-bottom:1px solid #dee2e6}.sidebar.sidebar-navigation.collapsing{position:fixed;z-index:1000}.sidebar.sidebar-navigation.show{position:fixed;z-index:1000}.sidebar.sidebar-navigation{min-height:100%}nav.quarto-secondary-nav{background-color:#fff;border-bottom:1px solid #dee2e6}.sidebar .sidebar-footer{visibility:visible;padding-top:1rem;position:inherit}.sidebar-tools-collapse{display:block}}#quarto-sidebar{transition:width .15s ease-in}#quarto-sidebar>*{padding-right:1em}@media(max-width: 991.98px){#quarto-sidebar .sidebar-menu-container{white-space:nowrap;min-width:225px}#quarto-sidebar.show{transition:width .15s ease-out}}@media(min-width: 992px){#quarto-sidebar{display:flex;flex-direction:column}.nav-page .nav-page-text,.sidebar-navigation .sidebar-section .sidebar-item{font-size:.875rem}.sidebar-navigation .sidebar-item{font-size:.925rem}.sidebar.sidebar-navigation{display:block;position:sticky}.sidebar-search{width:100%}.sidebar .sidebar-footer{visibility:visible}}@media(max-width: 991.98px){#quarto-sidebar-glass{position:fixed;top:0;bottom:0;left:0;right:0;background-color:rgba(255,255,255,0);transition:background-color .15s ease-in;z-index:-1}#quarto-sidebar-glass.collapsing{z-index:1000}#quarto-sidebar-glass.show{transition:background-color .15s ease-out;background-color:rgba(102,102,102,.4);z-index:1000}}.sidebar .sidebar-footer{padding:.5rem 1rem;align-self:flex-end;color:#6c757d;width:100%}.quarto-page-breadcrumbs .breadcrumb-item+.breadcrumb-item,.quarto-page-breadcrumbs .breadcrumb-item{padding-right:.33em;padding-left:0}.quarto-page-breadcrumbs .breadcrumb-item::before{padding-right:.33em}.quarto-sidebar-footer{font-size:.875em}.sidebar-section .bi-chevron-right{vertical-align:middle}.sidebar-section .bi-chevron-right::before{font-size:.9em}.notransition{-webkit-transition:none !important;-moz-transition:none !important;-o-transition:none !important;transition:none !important}.btn:focus:not(:focus-visible){box-shadow:none}.page-navigation{display:flex;justify-content:space-between}.nav-page{padding-bottom:.75em}.nav-page .bi{font-size:1.8rem;vertical-align:middle}.nav-page .nav-page-text{padding-left:.25em;padding-right:.25em}.nav-page a{color:#6c757d;text-decoration:none;display:flex;align-items:center}.nav-page a:hover{color:#1f66b6}.toc-actions{display:flex}.toc-actions p{margin-block-start:0;margin-block-end:0}.toc-actions a{text-decoration:none;color:inherit;font-weight:400}.toc-actions a:hover{color:#1f66b6}.toc-actions .action-links{margin-left:4px}.sidebar nav[role=doc-toc] .toc-actions .bi{margin-left:-4px;font-size:.7rem;color:#6c757d}.sidebar nav[role=doc-toc] .toc-actions .bi:before{padding-top:3px}#quarto-margin-sidebar .toc-actions .bi:before{margin-top:.3rem;font-size:.7rem;color:#6c757d;vertical-align:top}.sidebar nav[role=doc-toc] .toc-actions>div:first-of-type{margin-top:-3px}#quarto-margin-sidebar .toc-actions p,.sidebar nav[role=doc-toc] .toc-actions p{font-size:.875rem}.nav-footer .toc-actions{padding-bottom:.5em;padding-top:.5em}.nav-footer .toc-actions :first-child{margin-left:auto}.nav-footer .toc-actions :last-child{margin-right:auto}.nav-footer .toc-actions .action-links{display:flex}.nav-footer .toc-actions .action-links p{padding-right:1.5em}.nav-footer .toc-actions .action-links p:last-of-type{padding-right:0}.nav-footer{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:space-between;align-items:baseline;text-align:center;padding-top:.5rem;padding-bottom:.5rem;background-color:#fff}body.nav-fixed{padding-top:64px}.nav-footer-contents{color:#6c757d;margin-top:.25rem}.nav-footer{min-height:3.5em;color:#757575}.nav-footer a{color:#757575}.nav-footer .nav-footer-left{font-size:.825em}.nav-footer .nav-footer-center{font-size:.825em}.nav-footer .nav-footer-right{font-size:.825em}.nav-footer-left .footer-items,.nav-footer-center .footer-items,.nav-footer-right .footer-items{display:inline-flex;padding-top:.3em;padding-bottom:.3em;margin-bottom:0em}.nav-footer-left .footer-items .nav-link,.nav-footer-center .footer-items .nav-link,.nav-footer-right .footer-items .nav-link{padding-left:.6em;padding-right:.6em}.nav-footer-left{flex:1 1 0px;text-align:left}.nav-footer-right{flex:1 1 0px;text-align:right}.nav-footer-center{flex:1 1 0px;min-height:3em;text-align:center}.nav-footer-center .footer-items{justify-content:center}@media(max-width: 767.98px){.nav-footer-center{margin-top:3em}}.navbar .quarto-reader-toggle.reader .quarto-reader-toggle-btn{background-color:#fdfeff;border-radius:3px}.quarto-reader-toggle.reader.quarto-navigation-tool .quarto-reader-toggle-btn{background-color:#595959;border-radius:3px}.quarto-reader-toggle .quarto-reader-toggle-btn{display:inline-flex;padding-left:.2em;padding-right:.2em;margin-left:-0.2em;margin-right:-0.2em;text-align:center}.navbar .quarto-reader-toggle:not(.reader) .bi::before{background-image:url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="rgba(253, 254, 255, 1)" class="bi bi-body-text" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M0 .5A.5.5 0 0 1 .5 0h4a.5.5 0 0 1 0 1h-4A.5.5 0 0 1 0 .5Zm0 2A.5.5 0 0 1 .5 2h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5Zm9 0a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5Zm-9 2A.5.5 0 0 1 .5 4h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1-.5-.5Zm5 0a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5Zm7 0a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1-.5-.5Zm-12 2A.5.5 0 0 1 .5 6h6a.5.5 0 0 1 0 1h-6a.5.5 0 0 1-.5-.5Zm8 0a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5Zm-8 2A.5.5 0 0 1 .5 8h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5Zm7 0a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5Zm-7 2a.5.5 0 0 1 .5-.5h8a.5.5 0 0 1 0 1h-8a.5.5 0 0 1-.5-.5Zm0 2a.5.5 0 0 1 .5-.5h4a.5.5 0 0 1 0 1h-4a.5.5 0 0 1-.5-.5Zm0 2a.5.5 0 0 1 .5-.5h2a.5.5 0 0 1 0 1h-2a.5.5 0 0 1-.5-.5Z"/></svg>')}.navbar .quarto-reader-toggle.reader .bi::before{background-image:url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="rgba(39, 128, 227, 1)" class="bi bi-body-text" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M0 .5A.5.5 0 0 1 .5 0h4a.5.5 0 0 1 0 1h-4A.5.5 0 0 1 0 .5Zm0 2A.5.5 0 0 1 .5 2h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5Zm9 0a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5Zm-9 2A.5.5 0 0 1 .5 4h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1-.5-.5Zm5 0a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5Zm7 0a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1-.5-.5Zm-12 2A.5.5 0 0 1 .5 6h6a.5.5 0 0 1 0 1h-6a.5.5 0 0 1-.5-.5Zm8 0a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5Zm-8 2A.5.5 0 0 1 .5 8h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5Zm7 0a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5Zm-7 2a.5.5 0 0 1 .5-.5h8a.5.5 0 0 1 0 1h-8a.5.5 0 0 1-.5-.5Zm0 2a.5.5 0 0 1 .5-.5h4a.5.5 0 0 1 0 1h-4a.5.5 0 0 1-.5-.5Zm0 2a.5.5 0 0 1 .5-.5h2a.5.5 0 0 1 0 1h-2a.5.5 0 0 1-.5-.5Z"/></svg>')}.sidebar-navigation .quarto-reader-toggle:not(.reader) .bi::before{background-image:url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="rgba(89, 89, 89, 1)" class="bi bi-body-text" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M0 .5A.5.5 0 0 1 .5 0h4a.5.5 0 0 1 0 1h-4A.5.5 0 0 1 0 .5Zm0 2A.5.5 0 0 1 .5 2h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5Zm9 0a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5Zm-9 2A.5.5 0 0 1 .5 4h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1-.5-.5Zm5 0a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5Zm7 0a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1-.5-.5Zm-12 2A.5.5 0 0 1 .5 6h6a.5.5 0 0 1 0 1h-6a.5.5 0 0 1-.5-.5Zm8 0a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5Zm-8 2A.5.5 0 0 1 .5 8h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5Zm7 0a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5Zm-7 2a.5.5 0 0 1 .5-.5h8a.5.5 0 0 1 0 1h-8a.5.5 0 0 1-.5-.5Zm0 2a.5.5 0 0 1 .5-.5h4a.5.5 0 0 1 0 1h-4a.5.5 0 0 1-.5-.5Zm0 2a.5.5 0 0 1 .5-.5h2a.5.5 0 0 1 0 1h-2a.5.5 0 0 1-.5-.5Z"/></svg>')}.sidebar-navigation .quarto-reader-toggle.reader .bi::before{background-image:url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="rgba(255, 255, 255, 1)" class="bi bi-body-text" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M0 .5A.5.5 0 0 1 .5 0h4a.5.5 0 0 1 0 1h-4A.5.5 0 0 1 0 .5Zm0 2A.5.5 0 0 1 .5 2h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5Zm9 0a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5Zm-9 2A.5.5 0 0 1 .5 4h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1-.5-.5Zm5 0a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5Zm7 0a.5.5 0 0 1 .5-.5h3a.5.5 0 0 1 0 1h-3a.5.5 0 0 1-.5-.5Zm-12 2A.5.5 0 0 1 .5 6h6a.5.5 0 0 1 0 1h-6a.5.5 0 0 1-.5-.5Zm8 0a.5.5 0 0 1 .5-.5h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5Zm-8 2A.5.5 0 0 1 .5 8h5a.5.5 0 0 1 0 1h-5a.5.5 0 0 1-.5-.5Zm7 0a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5Zm-7 2a.5.5 0 0 1 .5-.5h8a.5.5 0 0 1 0 1h-8a.5.5 0 0 1-.5-.5Zm0 2a.5.5 0 0 1 .5-.5h4a.5.5 0 0 1 0 1h-4a.5.5 0 0 1-.5-.5Zm0 2a.5.5 0 0 1 .5-.5h2a.5.5 0 0 1 0 1h-2a.5.5 0 0 1-.5-.5Z"/></svg>')}#quarto-back-to-top{display:none;position:fixed;bottom:50px;background-color:#fff;border-radius:.25rem;box-shadow:0 .2rem .5rem #6c757d,0 0 .05rem #6c757d;color:#6c757d;text-decoration:none;font-size:.9em;text-align:center;left:50%;padding:.4rem .8rem;transform:translate(-50%, 0)}.aa-DetachedOverlay ul.aa-List,#quarto-search-results ul.aa-List{list-style:none;padding-left:0}.aa-DetachedOverlay .aa-Panel,#quarto-search-results .aa-Panel{background-color:#fff;position:absolute;z-index:2000}#quarto-search-results .aa-Panel{max-width:400px}#quarto-search input{font-size:.925rem}@media(min-width: 992px){.navbar #quarto-search{margin-left:.25rem;order:999}}@media(max-width: 991.98px){#quarto-sidebar .sidebar-search{display:none}}#quarto-sidebar .sidebar-search .aa-Autocomplete{width:100%}.navbar .aa-Autocomplete .aa-Form{width:180px}.navbar #quarto-search.type-overlay .aa-Autocomplete{width:40px}.navbar #quarto-search.type-overlay .aa-Autocomplete .aa-Form{background-color:inherit;border:none}.navbar #quarto-search.type-overlay .aa-Autocomplete .aa-Form:focus-within{box-shadow:none;outline:none}.navbar #quarto-search.type-overlay .aa-Autocomplete .aa-Form .aa-InputWrapper{display:none}.navbar #quarto-search.type-overlay .aa-Autocomplete .aa-Form .aa-InputWrapper:focus-within{display:inherit}.navbar #quarto-search.type-overlay .aa-Autocomplete .aa-Form .aa-Label svg,.navbar #quarto-search.type-overlay .aa-Autocomplete .aa-Form .aa-LoadingIndicator svg{width:26px;height:26px;color:#fdfeff;opacity:1}.navbar #quarto-search.type-overlay .aa-Autocomplete svg.aa-SubmitIcon{width:26px;height:26px;color:#fdfeff;opacity:1}.aa-Autocomplete .aa-Form,.aa-DetachedFormContainer .aa-Form{align-items:center;background-color:#fff;border:1px solid #ced4da;border-radius:.25rem;color:#373a3c;display:flex;line-height:1em;margin:0;position:relative;width:100%}.aa-Autocomplete .aa-Form:focus-within,.aa-DetachedFormContainer .aa-Form:focus-within{box-shadow:rgba(39,128,227,.6) 0 0 0 1px;outline:currentColor none medium}.aa-Autocomplete .aa-Form .aa-InputWrapperPrefix,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperPrefix{align-items:center;display:flex;flex-shrink:0;order:1}.aa-Autocomplete .aa-Form .aa-InputWrapperPrefix .aa-Label,.aa-Autocomplete .aa-Form .aa-InputWrapperPrefix .aa-LoadingIndicator,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperPrefix .aa-Label,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperPrefix .aa-LoadingIndicator{cursor:initial;flex-shrink:0;padding:0;text-align:left}.aa-Autocomplete .aa-Form .aa-InputWrapperPrefix .aa-Label svg,.aa-Autocomplete .aa-Form .aa-InputWrapperPrefix .aa-LoadingIndicator svg,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperPrefix .aa-Label svg,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperPrefix .aa-LoadingIndicator svg{color:#373a3c;opacity:.5}.aa-Autocomplete .aa-Form .aa-InputWrapperPrefix .aa-SubmitButton,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperPrefix .aa-SubmitButton{appearance:none;background:none;border:0;margin:0}.aa-Autocomplete .aa-Form .aa-InputWrapperPrefix .aa-LoadingIndicator,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperPrefix .aa-LoadingIndicator{align-items:center;display:flex;justify-content:center}.aa-Autocomplete .aa-Form .aa-InputWrapperPrefix .aa-LoadingIndicator[hidden],.aa-DetachedFormContainer .aa-Form .aa-InputWrapperPrefix .aa-LoadingIndicator[hidden]{display:none}.aa-Autocomplete .aa-Form .aa-InputWrapper,.aa-DetachedFormContainer .aa-Form .aa-InputWrapper{order:3;position:relative;width:100%}.aa-Autocomplete .aa-Form .aa-InputWrapper .aa-Input,.aa-DetachedFormContainer .aa-Form .aa-InputWrapper .aa-Input{appearance:none;background:none;border:0;color:#373a3c;font:inherit;height:calc(1.5em + .1rem + 2px);padding:0;width:100%}.aa-Autocomplete .aa-Form .aa-InputWrapper .aa-Input::placeholder,.aa-DetachedFormContainer .aa-Form .aa-InputWrapper .aa-Input::placeholder{color:#373a3c;opacity:.8}.aa-Autocomplete .aa-Form .aa-InputWrapper .aa-Input:focus,.aa-DetachedFormContainer .aa-Form .aa-InputWrapper .aa-Input:focus{border-color:none;box-shadow:none;outline:none}.aa-Autocomplete .aa-Form .aa-InputWrapper .aa-Input::-webkit-search-decoration,.aa-Autocomplete .aa-Form .aa-InputWrapper .aa-Input::-webkit-search-cancel-button,.aa-Autocomplete .aa-Form .aa-InputWrapper .aa-Input::-webkit-search-results-button,.aa-Autocomplete .aa-Form .aa-InputWrapper .aa-Input::-webkit-search-results-decoration,.aa-DetachedFormContainer .aa-Form .aa-InputWrapper .aa-Input::-webkit-search-decoration,.aa-DetachedFormContainer .aa-Form .aa-InputWrapper .aa-Input::-webkit-search-cancel-button,.aa-DetachedFormContainer .aa-Form .aa-InputWrapper .aa-Input::-webkit-search-results-button,.aa-DetachedFormContainer .aa-Form .aa-InputWrapper .aa-Input::-webkit-search-results-decoration{display:none}.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix{align-items:center;display:flex;order:4}.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-ClearButton,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-ClearButton{align-items:center;background:none;border:0;color:#373a3c;opacity:.8;cursor:pointer;display:flex;margin:0;width:calc(1.5em + .1rem + 2px)}.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-ClearButton:hover,.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-ClearButton:focus,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-ClearButton:hover,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-ClearButton:focus{color:#373a3c;opacity:.8}.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-ClearButton[hidden],.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-ClearButton[hidden]{display:none}.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-ClearButton svg,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-ClearButton svg{width:calc(1.5em + 0.75rem + 2px)}.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-CopyButton,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-CopyButton{border:none;align-items:center;background:none;color:#373a3c;opacity:.4;font-size:.7rem;cursor:pointer;display:none;margin:0;width:calc(1em + .1rem + 2px)}.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-CopyButton:hover,.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-CopyButton:focus,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-CopyButton:hover,.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-CopyButton:focus{color:#373a3c;opacity:.8}.aa-Autocomplete .aa-Form .aa-InputWrapperSuffix .aa-CopyButton[hidden],.aa-DetachedFormContainer .aa-Form .aa-InputWrapperSuffix .aa-CopyButton[hidden]{display:none}.aa-PanelLayout:empty{display:none}.quarto-search-no-results.no-query{display:none}.aa-Source:has(.no-query){display:none}#quarto-search-results .aa-Panel{border:solid #ced4da 1px}#quarto-search-results .aa-SourceNoResults{width:398px}.aa-DetachedOverlay .aa-Panel,#quarto-search-results .aa-Panel{max-height:65vh;overflow-y:auto;font-size:.925rem}.aa-DetachedOverlay .aa-SourceNoResults,#quarto-search-results .aa-SourceNoResults{height:60px;display:flex;justify-content:center;align-items:center}.aa-DetachedOverlay .search-error,#quarto-search-results .search-error{padding-top:10px;padding-left:20px;padding-right:20px;cursor:default}.aa-DetachedOverlay .search-error .search-error-title,#quarto-search-results .search-error .search-error-title{font-size:1.1rem;margin-bottom:.5rem}.aa-DetachedOverlay .search-error .search-error-title .search-error-icon,#quarto-search-results .search-error .search-error-title .search-error-icon{margin-right:8px}.aa-DetachedOverlay .search-error .search-error-text,#quarto-search-results .search-error .search-error-text{font-weight:300}.aa-DetachedOverlay .search-result-text,#quarto-search-results .search-result-text{font-weight:300;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;line-height:1.2rem;max-height:2.4rem}.aa-DetachedOverlay .aa-SourceHeader .search-result-header,#quarto-search-results .aa-SourceHeader .search-result-header{font-size:.875rem;background-color:#f2f2f2;padding-left:14px;padding-bottom:4px;padding-top:4px}.aa-DetachedOverlay .aa-SourceHeader .search-result-header-no-results,#quarto-search-results .aa-SourceHeader .search-result-header-no-results{display:none}.aa-DetachedOverlay .aa-SourceFooter .algolia-search-logo,#quarto-search-results .aa-SourceFooter .algolia-search-logo{width:110px;opacity:.85;margin:8px;float:right}.aa-DetachedOverlay .search-result-section,#quarto-search-results .search-result-section{font-size:.925em}.aa-DetachedOverlay a.search-result-link,#quarto-search-results a.search-result-link{color:inherit;text-decoration:none}.aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item,#quarto-search-results li.aa-Item[aria-selected=true] .search-item{background-color:#2780e3}.aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item.search-result-more,.aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item .search-result-section,.aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item .search-result-text,.aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item .search-result-title-container,.aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item .search-result-text-container,#quarto-search-results li.aa-Item[aria-selected=true] .search-item.search-result-more,#quarto-search-results li.aa-Item[aria-selected=true] .search-item .search-result-section,#quarto-search-results li.aa-Item[aria-selected=true] .search-item .search-result-text,#quarto-search-results li.aa-Item[aria-selected=true] .search-item .search-result-title-container,#quarto-search-results li.aa-Item[aria-selected=true] .search-item .search-result-text-container{color:#fff;background-color:#2780e3}.aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item mark.search-match,.aa-DetachedOverlay li.aa-Item[aria-selected=true] .search-item .search-match.mark,#quarto-search-results li.aa-Item[aria-selected=true] .search-item mark.search-match,#quarto-search-results li.aa-Item[aria-selected=true] .search-item .search-match.mark{color:#fff;background-color:#4b95e8}.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item,#quarto-search-results li.aa-Item[aria-selected=false] .search-item{background-color:#fff}.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item.search-result-more,.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item .search-result-section,.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item .search-result-text,.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item .search-result-title-container,.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item .search-result-text-container,#quarto-search-results li.aa-Item[aria-selected=false] .search-item.search-result-more,#quarto-search-results li.aa-Item[aria-selected=false] .search-item .search-result-section,#quarto-search-results li.aa-Item[aria-selected=false] .search-item .search-result-text,#quarto-search-results li.aa-Item[aria-selected=false] .search-item .search-result-title-container,#quarto-search-results li.aa-Item[aria-selected=false] .search-item .search-result-text-container{color:#373a3c}.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item mark.search-match,.aa-DetachedOverlay li.aa-Item[aria-selected=false] .search-item .search-match.mark,#quarto-search-results li.aa-Item[aria-selected=false] .search-item mark.search-match,#quarto-search-results li.aa-Item[aria-selected=false] .search-item .search-match.mark{color:inherit;background-color:#e5effc}.aa-DetachedOverlay .aa-Item .search-result-doc:not(.document-selectable) .search-result-title-container,#quarto-search-results .aa-Item .search-result-doc:not(.document-selectable) .search-result-title-container{background-color:#fff;color:#373a3c}.aa-DetachedOverlay .aa-Item .search-result-doc:not(.document-selectable) .search-result-text-container,#quarto-search-results .aa-Item .search-result-doc:not(.document-selectable) .search-result-text-container{padding-top:0px}.aa-DetachedOverlay li.aa-Item .search-result-doc.document-selectable .search-result-text-container,#quarto-search-results li.aa-Item .search-result-doc.document-selectable .search-result-text-container{margin-top:-4px}.aa-DetachedOverlay .aa-Item,#quarto-search-results .aa-Item{cursor:pointer}.aa-DetachedOverlay .aa-Item .search-item,#quarto-search-results .aa-Item .search-item{border-left:none;border-right:none;border-top:none;background-color:#fff;border-color:#ced4da;color:#373a3c}.aa-DetachedOverlay .aa-Item .search-item p,#quarto-search-results .aa-Item .search-item p{margin-top:0;margin-bottom:0}.aa-DetachedOverlay .aa-Item .search-item i.bi,#quarto-search-results .aa-Item .search-item i.bi{padding-left:8px;padding-right:8px;font-size:1.3em}.aa-DetachedOverlay .aa-Item .search-item .search-result-title,#quarto-search-results .aa-Item .search-item .search-result-title{margin-top:.3em;margin-bottom:.1rem}.aa-DetachedOverlay .aa-Item .search-result-title-container,#quarto-search-results .aa-Item .search-result-title-container{font-size:1em;display:flex;padding:6px 4px 6px 4px}.aa-DetachedOverlay .aa-Item .search-result-text-container,#quarto-search-results .aa-Item .search-result-text-container{padding-bottom:8px;padding-right:8px;margin-left:44px}.aa-DetachedOverlay .aa-Item .search-result-doc-section,.aa-DetachedOverlay .aa-Item .search-result-more,#quarto-search-results .aa-Item .search-result-doc-section,#quarto-search-results .aa-Item .search-result-more{padding-top:8px;padding-bottom:8px;padding-left:44px}.aa-DetachedOverlay .aa-Item .search-result-more,#quarto-search-results .aa-Item .search-result-more{font-size:.8em;font-weight:400}.aa-DetachedOverlay .aa-Item .search-result-doc,#quarto-search-results .aa-Item .search-result-doc{border-top:1px solid #ced4da}.aa-DetachedSearchButton{background:none;border:none}.aa-DetachedSearchButton .aa-DetachedSearchButtonPlaceholder{display:none}.navbar .aa-DetachedSearchButton .aa-DetachedSearchButtonIcon{color:#fdfeff}.sidebar-tools-collapse #quarto-search,.sidebar-tools-main #quarto-search{display:inline}.sidebar-tools-collapse #quarto-search .aa-Autocomplete,.sidebar-tools-main #quarto-search .aa-Autocomplete{display:inline}.sidebar-tools-collapse #quarto-search .aa-DetachedSearchButton,.sidebar-tools-main #quarto-search .aa-DetachedSearchButton{padding-left:4px;padding-right:4px}.sidebar-tools-collapse #quarto-search .aa-DetachedSearchButton .aa-DetachedSearchButtonIcon,.sidebar-tools-main #quarto-search .aa-DetachedSearchButton .aa-DetachedSearchButtonIcon{color:#595959}.sidebar-tools-collapse #quarto-search .aa-DetachedSearchButton .aa-DetachedSearchButtonIcon .aa-SubmitIcon,.sidebar-tools-main #quarto-search .aa-DetachedSearchButton .aa-DetachedSearchButtonIcon .aa-SubmitIcon{margin-top:-3px}.aa-DetachedContainer{background:rgba(255,255,255,.65);width:90%;bottom:0;box-shadow:rgba(206,212,218,.6) 0 0 0 1px;outline:currentColor none medium;display:flex;flex-direction:column;left:0;margin:0;overflow:hidden;padding:0;position:fixed;right:0;top:0;z-index:1101}.aa-DetachedContainer::after{height:32px}.aa-DetachedContainer .aa-SourceHeader{margin:var(--aa-spacing-half) 0 var(--aa-spacing-half) 2px}.aa-DetachedContainer .aa-Panel{background-color:#fff;border-radius:0;box-shadow:none;flex-grow:1;margin:0;padding:0;position:relative}.aa-DetachedContainer .aa-PanelLayout{bottom:0;box-shadow:none;left:0;margin:0;max-height:none;overflow-y:auto;position:absolute;right:0;top:0;width:100%}.aa-DetachedFormContainer{background-color:#fff;border-bottom:1px solid #ced4da;display:flex;flex-direction:row;justify-content:space-between;margin:0;padding:.5em}.aa-DetachedCancelButton{background:none;font-size:.8em;border:0;border-radius:3px;color:#373a3c;cursor:pointer;margin:0 0 0 .5em;padding:0 .5em}.aa-DetachedCancelButton:hover,.aa-DetachedCancelButton:focus{box-shadow:rgba(39,128,227,.6) 0 0 0 1px;outline:currentColor none medium}.aa-DetachedContainer--modal{bottom:inherit;height:auto;margin:0 auto;position:absolute;top:100px;border-radius:6px;max-width:850px}@media(max-width: 575.98px){.aa-DetachedContainer--modal{width:100%;top:0px;border-radius:0px;border:none}}.aa-DetachedContainer--modal .aa-PanelLayout{max-height:var(--aa-detached-modal-max-height);padding-bottom:var(--aa-spacing-half);position:static}.aa-Detached{height:100vh;overflow:hidden}.aa-DetachedOverlay{background-color:rgba(55,58,60,.4);position:fixed;left:0;right:0;top:0;margin:0;padding:0;height:100vh;z-index:1100}.quarto-listing{padding-bottom:1em}.listing-pagination{padding-top:.5em}ul.pagination{float:right;padding-left:8px;padding-top:.5em}ul.pagination li{padding-right:.75em}ul.pagination li.disabled a,ul.pagination li.active a{color:#373a3c;text-decoration:none}ul.pagination li:last-of-type{padding-right:0}.listing-actions-group{display:flex}.quarto-listing-filter{margin-bottom:1em;width:200px;margin-left:auto}.quarto-listing-sort{margin-bottom:1em;margin-right:auto;width:auto}.quarto-listing-sort .input-group-text{font-size:.8em}.input-group-text{border-right:none}.quarto-listing-sort select.form-select{font-size:.8em}.listing-no-matching{text-align:center;padding-top:2em;padding-bottom:3em;font-size:1em}#quarto-margin-sidebar .quarto-listing-category{padding-top:0;font-size:1rem}#quarto-margin-sidebar .quarto-listing-category-title{cursor:pointer;font-weight:600;font-size:1rem}.quarto-listing-category .category{cursor:pointer}.quarto-listing-category .category.active{font-weight:600}.quarto-listing-category.category-cloud{display:flex;flex-wrap:wrap;align-items:baseline}.quarto-listing-category.category-cloud .category{padding-right:5px}.quarto-listing-category.category-cloud .category-cloud-1{font-size:.75em}.quarto-listing-category.category-cloud .category-cloud-2{font-size:.95em}.quarto-listing-category.category-cloud .category-cloud-3{font-size:1.15em}.quarto-listing-category.category-cloud .category-cloud-4{font-size:1.35em}.quarto-listing-category.category-cloud .category-cloud-5{font-size:1.55em}.quarto-listing-category.category-cloud .category-cloud-6{font-size:1.75em}.quarto-listing-category.category-cloud .category-cloud-7{font-size:1.95em}.quarto-listing-category.category-cloud .category-cloud-8{font-size:2.15em}.quarto-listing-category.category-cloud .category-cloud-9{font-size:2.35em}.quarto-listing-category.category-cloud .category-cloud-10{font-size:2.55em}.quarto-listing-cols-1{grid-template-columns:repeat(1, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-1{grid-template-columns:repeat(1, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-1{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-2{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-2{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-2{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-3{grid-template-columns:repeat(3, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-3{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-3{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-4{grid-template-columns:repeat(4, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-4{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-4{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-5{grid-template-columns:repeat(5, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-5{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-5{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-6{grid-template-columns:repeat(6, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-6{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-6{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-7{grid-template-columns:repeat(7, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-7{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-7{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-8{grid-template-columns:repeat(8, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-8{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-8{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-9{grid-template-columns:repeat(9, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-9{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-9{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-10{grid-template-columns:repeat(10, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-10{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-10{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-11{grid-template-columns:repeat(11, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-11{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-11{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-cols-12{grid-template-columns:repeat(12, minmax(0, 1fr));gap:1.5em}@media(max-width: 767.98px){.quarto-listing-cols-12{grid-template-columns:repeat(2, minmax(0, 1fr));gap:1.5em}}@media(max-width: 575.98px){.quarto-listing-cols-12{grid-template-columns:minmax(0, 1fr);gap:1.5em}}.quarto-listing-grid{gap:1.5em}.quarto-grid-item.borderless{border:none}.quarto-grid-item.borderless .listing-categories .listing-category:last-of-type,.quarto-grid-item.borderless .listing-categories .listing-category:first-of-type{padding-left:0}.quarto-grid-item.borderless .listing-categories .listing-category{border:0}.quarto-grid-link{text-decoration:none;color:inherit}.quarto-grid-link:hover{text-decoration:none;color:inherit}.quarto-grid-item h5.title,.quarto-grid-item .title.h5{margin-top:0;margin-bottom:0}.quarto-grid-item .card-footer{display:flex;justify-content:space-between;font-size:.8em}.quarto-grid-item .card-footer p{margin-bottom:0}.quarto-grid-item p.card-img-top{margin-bottom:0}.quarto-grid-item p.card-img-top>img{object-fit:cover}.quarto-grid-item .card-other-values{margin-top:.5em;font-size:.8em}.quarto-grid-item .card-other-values tr{margin-bottom:.5em}.quarto-grid-item .card-other-values tr>td:first-of-type{font-weight:600;padding-right:1em;padding-left:1em;vertical-align:top}.quarto-grid-item div.post-contents{display:flex;flex-direction:column;text-decoration:none;height:100%}.quarto-grid-item .listing-item-img-placeholder{background-color:#adb5bd;flex-shrink:0}.quarto-grid-item .card-attribution{padding-top:1em;display:flex;gap:1em;text-transform:uppercase;color:#6c757d;font-weight:500;flex-grow:10;align-items:flex-end}.quarto-grid-item .description{padding-bottom:1em}.quarto-grid-item .card-attribution .date{align-self:flex-end}.quarto-grid-item .card-attribution.justify{justify-content:space-between}.quarto-grid-item .card-attribution.start{justify-content:flex-start}.quarto-grid-item .card-attribution.end{justify-content:flex-end}.quarto-grid-item .card-title{margin-bottom:.1em}.quarto-grid-item .card-subtitle{padding-top:.25em}.quarto-grid-item .card-text{font-size:.9em}.quarto-grid-item .listing-reading-time{padding-bottom:.25em}.quarto-grid-item .card-text-small{font-size:.8em}.quarto-grid-item .card-subtitle.subtitle{font-size:.9em;font-weight:600;padding-bottom:.5em}.quarto-grid-item .listing-categories{display:flex;flex-wrap:wrap;padding-bottom:5px}.quarto-grid-item .listing-categories .listing-category{color:#6c757d;border:solid 1px #dee2e6;border-radius:.25rem;text-transform:uppercase;font-size:.65em;padding-left:.5em;padding-right:.5em;padding-top:.15em;padding-bottom:.15em;cursor:pointer;margin-right:4px;margin-bottom:4px}.quarto-grid-item.card-right{text-align:right}.quarto-grid-item.card-right .listing-categories{justify-content:flex-end}.quarto-grid-item.card-left{text-align:left}.quarto-grid-item.card-center{text-align:center}.quarto-grid-item.card-center .listing-description{text-align:justify}.quarto-grid-item.card-center .listing-categories{justify-content:center}table.quarto-listing-table td.image{padding:0px}table.quarto-listing-table td.image img{width:100%;max-width:50px;object-fit:contain}table.quarto-listing-table a{text-decoration:none}table.quarto-listing-table th a{color:inherit}table.quarto-listing-table th a.asc:after{margin-bottom:-2px;margin-left:5px;display:inline-block;height:1rem;width:1rem;background-repeat:no-repeat;background-size:1rem 1rem;background-image:url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-sort-up" viewBox="0 0 16 16"><path d="M3.5 12.5a.5.5 0 0 1-1 0V3.707L1.354 4.854a.5.5 0 1 1-.708-.708l2-1.999.007-.007a.498.498 0 0 1 .7.006l2 2a.5.5 0 1 1-.707.708L3.5 3.707V12.5zm3.5-9a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5zM7.5 6a.5.5 0 0 0 0 1h5a.5.5 0 0 0 0-1h-5zm0 3a.5.5 0 0 0 0 1h3a.5.5 0 0 0 0-1h-3zm0 3a.5.5 0 0 0 0 1h1a.5.5 0 0 0 0-1h-1z"/></svg>');content:""}table.quarto-listing-table th a.desc:after{margin-bottom:-2px;margin-left:5px;display:inline-block;height:1rem;width:1rem;background-repeat:no-repeat;background-size:1rem 1rem;background-image:url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-sort-down" viewBox="0 0 16 16"><path d="M3.5 2.5a.5.5 0 0 0-1 0v8.793l-1.146-1.147a.5.5 0 0 0-.708.708l2 1.999.007.007a.497.497 0 0 0 .7-.006l2-2a.5.5 0 0 0-.707-.708L3.5 11.293V2.5zm3.5 1a.5.5 0 0 1 .5-.5h7a.5.5 0 0 1 0 1h-7a.5.5 0 0 1-.5-.5zM7.5 6a.5.5 0 0 0 0 1h5a.5.5 0 0 0 0-1h-5zm0 3a.5.5 0 0 0 0 1h3a.5.5 0 0 0 0-1h-3zm0 3a.5.5 0 0 0 0 1h1a.5.5 0 0 0 0-1h-1z"/></svg>');content:""}table.quarto-listing-table.table-hover td{cursor:pointer}.quarto-post.image-left{flex-direction:row}.quarto-post.image-right{flex-direction:row-reverse}@media(max-width: 767.98px){.quarto-post.image-right,.quarto-post.image-left{gap:0em;flex-direction:column}.quarto-post .metadata{padding-bottom:1em;order:2}.quarto-post .body{order:1}.quarto-post .thumbnail{order:3}}.list.quarto-listing-default div:last-of-type{border-bottom:none}@media(min-width: 992px){.quarto-listing-container-default{margin-right:2em}}div.quarto-post{display:flex;gap:2em;margin-bottom:1.5em;border-bottom:1px solid #dee2e6}@media(max-width: 767.98px){div.quarto-post{padding-bottom:1em}}div.quarto-post .metadata{flex-basis:20%;flex-grow:0;margin-top:.2em;flex-shrink:10}div.quarto-post .thumbnail{flex-basis:30%;flex-grow:0;flex-shrink:0}div.quarto-post .thumbnail img{margin-top:.4em;width:100%;object-fit:cover}div.quarto-post .body{flex-basis:45%;flex-grow:1;flex-shrink:0}div.quarto-post .body h3.listing-title,div.quarto-post .body .listing-title.h3{margin-top:0px;margin-bottom:0px;border-bottom:none}div.quarto-post .body .listing-subtitle{font-size:.875em;margin-bottom:.5em;margin-top:.2em}div.quarto-post .body .description{font-size:.9em}div.quarto-post a{color:#373a3c;display:flex;flex-direction:column;text-decoration:none}div.quarto-post a div.description{flex-shrink:0}div.quarto-post .metadata{display:flex;flex-direction:column;font-size:.8em;font-family:var(--bs-font-sans-serif);flex-basis:33%}div.quarto-post .listing-categories{display:flex;flex-wrap:wrap;padding-bottom:5px}div.quarto-post .listing-categories .listing-category{color:#6c757d;border:solid 1px #dee2e6;border-radius:.25rem;text-transform:uppercase;font-size:.65em;padding-left:.5em;padding-right:.5em;padding-top:.15em;padding-bottom:.15em;cursor:pointer;margin-right:4px;margin-bottom:4px}div.quarto-post .listing-description{margin-bottom:.5em}div.quarto-about-jolla{display:flex !important;flex-direction:column;align-items:center;margin-top:10%;padding-bottom:1em}div.quarto-about-jolla .about-image{object-fit:cover;margin-left:auto;margin-right:auto;margin-bottom:1.5em}div.quarto-about-jolla img.round{border-radius:50%}div.quarto-about-jolla img.rounded{border-radius:10px}div.quarto-about-jolla .quarto-title h1.title,div.quarto-about-jolla .quarto-title .title.h1{text-align:center}div.quarto-about-jolla .quarto-title .description{text-align:center}div.quarto-about-jolla h2,div.quarto-about-jolla .h2{border-bottom:none}div.quarto-about-jolla .about-sep{width:60%}div.quarto-about-jolla main{text-align:center}div.quarto-about-jolla .about-links{display:flex}@media(min-width: 992px){div.quarto-about-jolla .about-links{flex-direction:row;column-gap:.8em;row-gap:15px;flex-wrap:wrap}}@media(max-width: 991.98px){div.quarto-about-jolla .about-links{flex-direction:column;row-gap:1em;width:100%;padding-bottom:1.5em}}div.quarto-about-jolla .about-link{color:#686d71;text-decoration:none;border:solid 1px}@media(min-width: 992px){div.quarto-about-jolla .about-link{font-size:.8em;padding:.25em .5em;border-radius:4px}}@media(max-width: 991.98px){div.quarto-about-jolla .about-link{font-size:1.1em;padding:.5em .5em;text-align:center;border-radius:6px}}div.quarto-about-jolla .about-link:hover{color:#2780e3}div.quarto-about-jolla .about-link i.bi{margin-right:.15em}div.quarto-about-solana{display:flex !important;flex-direction:column;padding-top:3em !important;padding-bottom:1em}div.quarto-about-solana .about-entity{display:flex !important;align-items:start;justify-content:space-between}@media(min-width: 992px){div.quarto-about-solana .about-entity{flex-direction:row}}@media(max-width: 991.98px){div.quarto-about-solana .about-entity{flex-direction:column-reverse;align-items:center;text-align:center}}div.quarto-about-solana .about-entity .entity-contents{display:flex;flex-direction:column}@media(max-width: 767.98px){div.quarto-about-solana .about-entity .entity-contents{width:100%}}div.quarto-about-solana .about-entity .about-image{object-fit:cover}@media(max-width: 991.98px){div.quarto-about-solana .about-entity .about-image{margin-bottom:1.5em}}div.quarto-about-solana .about-entity img.round{border-radius:50%}div.quarto-about-solana .about-entity img.rounded{border-radius:10px}div.quarto-about-solana .about-entity .about-links{display:flex;justify-content:left;padding-bottom:1.2em}@media(min-width: 992px){div.quarto-about-solana .about-entity .about-links{flex-direction:row;column-gap:.8em;row-gap:15px;flex-wrap:wrap}}@media(max-width: 991.98px){div.quarto-about-solana .about-entity .about-links{flex-direction:column;row-gap:1em;width:100%;padding-bottom:1.5em}}div.quarto-about-solana .about-entity .about-link{color:#686d71;text-decoration:none;border:solid 1px}@media(min-width: 992px){div.quarto-about-solana .about-entity .about-link{font-size:.8em;padding:.25em .5em;border-radius:4px}}@media(max-width: 991.98px){div.quarto-about-solana .about-entity .about-link{font-size:1.1em;padding:.5em .5em;text-align:center;border-radius:6px}}div.quarto-about-solana .about-entity .about-link:hover{color:#2780e3}div.quarto-about-solana .about-entity .about-link i.bi{margin-right:.15em}div.quarto-about-solana .about-contents{padding-right:1.5em;flex-basis:0;flex-grow:1}div.quarto-about-solana .about-contents main.content{margin-top:0}div.quarto-about-solana .about-contents h2,div.quarto-about-solana .about-contents .h2{border-bottom:none}div.quarto-about-trestles{display:flex !important;flex-direction:row;padding-top:3em !important;padding-bottom:1em}@media(max-width: 991.98px){div.quarto-about-trestles{flex-direction:column;padding-top:0em !important}}div.quarto-about-trestles .about-entity{display:flex !important;flex-direction:column;align-items:center;text-align:center;padding-right:1em}@media(min-width: 992px){div.quarto-about-trestles .about-entity{flex:0 0 42%}}div.quarto-about-trestles .about-entity .about-image{object-fit:cover;margin-bottom:1.5em}div.quarto-about-trestles .about-entity img.round{border-radius:50%}div.quarto-about-trestles .about-entity img.rounded{border-radius:10px}div.quarto-about-trestles .about-entity .about-links{display:flex;justify-content:center}@media(min-width: 992px){div.quarto-about-trestles .about-entity .about-links{flex-direction:row;column-gap:.8em;row-gap:15px;flex-wrap:wrap}}@media(max-width: 991.98px){div.quarto-about-trestles .about-entity .about-links{flex-direction:column;row-gap:1em;width:100%;padding-bottom:1.5em}}div.quarto-about-trestles .about-entity .about-link{color:#686d71;text-decoration:none;border:solid 1px}@media(min-width: 992px){div.quarto-about-trestles .about-entity .about-link{font-size:.8em;padding:.25em .5em;border-radius:4px}}@media(max-width: 991.98px){div.quarto-about-trestles .about-entity .about-link{font-size:1.1em;padding:.5em .5em;text-align:center;border-radius:6px}}div.quarto-about-trestles .about-entity .about-link:hover{color:#2780e3}div.quarto-about-trestles .about-entity .about-link i.bi{margin-right:.15em}div.quarto-about-trestles .about-contents{flex-basis:0;flex-grow:1}div.quarto-about-trestles .about-contents h2,div.quarto-about-trestles .about-contents .h2{border-bottom:none}@media(min-width: 992px){div.quarto-about-trestles .about-contents{border-left:solid 1px #dee2e6;padding-left:1.5em}}div.quarto-about-trestles .about-contents main.content{margin-top:0}div.quarto-about-marquee{padding-bottom:1em}div.quarto-about-marquee .about-contents{display:flex;flex-direction:column}div.quarto-about-marquee .about-image{max-height:550px;margin-bottom:1.5em;object-fit:cover}div.quarto-about-marquee img.round{border-radius:50%}div.quarto-about-marquee img.rounded{border-radius:10px}div.quarto-about-marquee h2,div.quarto-about-marquee .h2{border-bottom:none}div.quarto-about-marquee .about-links{display:flex;justify-content:center;padding-top:1.5em}@media(min-width: 992px){div.quarto-about-marquee .about-links{flex-direction:row;column-gap:.8em;row-gap:15px;flex-wrap:wrap}}@media(max-width: 991.98px){div.quarto-about-marquee .about-links{flex-direction:column;row-gap:1em;width:100%;padding-bottom:1.5em}}div.quarto-about-marquee .about-link{color:#686d71;text-decoration:none;border:solid 1px}@media(min-width: 992px){div.quarto-about-marquee .about-link{font-size:.8em;padding:.25em .5em;border-radius:4px}}@media(max-width: 991.98px){div.quarto-about-marquee .about-link{font-size:1.1em;padding:.5em .5em;text-align:center;border-radius:6px}}div.quarto-about-marquee .about-link:hover{color:#2780e3}div.quarto-about-marquee .about-link i.bi{margin-right:.15em}@media(min-width: 992px){div.quarto-about-marquee .about-link{border:none}}div.quarto-about-broadside{display:flex;flex-direction:column;padding-bottom:1em}div.quarto-about-broadside .about-main{display:flex !important;padding-top:0 !important}@media(min-width: 992px){div.quarto-about-broadside .about-main{flex-direction:row;align-items:flex-start}}@media(max-width: 991.98px){div.quarto-about-broadside .about-main{flex-direction:column}}@media(max-width: 991.98px){div.quarto-about-broadside .about-main .about-entity{flex-shrink:0;width:100%;height:450px;margin-bottom:1.5em;background-size:cover;background-repeat:no-repeat}}@media(min-width: 992px){div.quarto-about-broadside .about-main .about-entity{flex:0 10 50%;margin-right:1.5em;width:100%;height:100%;background-size:100%;background-repeat:no-repeat}}div.quarto-about-broadside .about-main .about-contents{padding-top:14px;flex:0 0 50%}div.quarto-about-broadside h2,div.quarto-about-broadside .h2{border-bottom:none}div.quarto-about-broadside .about-sep{margin-top:1.5em;width:60%;align-self:center}div.quarto-about-broadside .about-links{display:flex;justify-content:center;column-gap:20px;padding-top:1.5em}@media(min-width: 992px){div.quarto-about-broadside .about-links{flex-direction:row;column-gap:.8em;row-gap:15px;flex-wrap:wrap}}@media(max-width: 991.98px){div.quarto-about-broadside .about-links{flex-direction:column;row-gap:1em;width:100%;padding-bottom:1.5em}}div.quarto-about-broadside .about-link{color:#686d71;text-decoration:none;border:solid 1px}@media(min-width: 992px){div.quarto-about-broadside .about-link{font-size:.8em;padding:.25em .5em;border-radius:4px}}@media(max-width: 991.98px){div.quarto-about-broadside .about-link{font-size:1.1em;padding:.5em .5em;text-align:center;border-radius:6px}}div.quarto-about-broadside .about-link:hover{color:#2780e3}div.quarto-about-broadside .about-link i.bi{margin-right:.15em}@media(min-width: 992px){div.quarto-about-broadside .about-link{border:none}}.tippy-box[data-theme~=quarto]{background-color:#fff;border:solid 1px #dee2e6;border-radius:.25rem;color:#373a3c;font-size:.875rem}.tippy-box[data-theme~=quarto]>.tippy-backdrop{background-color:#fff}.tippy-box[data-theme~=quarto]>.tippy-arrow:after,.tippy-box[data-theme~=quarto]>.tippy-svg-arrow:after{content:"";position:absolute;z-index:-1}.tippy-box[data-theme~=quarto]>.tippy-arrow:after{border-color:rgba(0,0,0,0);border-style:solid}.tippy-box[data-placement^=top]>.tippy-arrow:before{bottom:-6px}.tippy-box[data-placement^=bottom]>.tippy-arrow:before{top:-6px}.tippy-box[data-placement^=right]>.tippy-arrow:before{left:-6px}.tippy-box[data-placement^=left]>.tippy-arrow:before{right:-6px}.tippy-box[data-theme~=quarto][data-placement^=top]>.tippy-arrow:before{border-top-color:#fff}.tippy-box[data-theme~=quarto][data-placement^=top]>.tippy-arrow:after{border-top-color:#dee2e6;border-width:7px 7px 0;top:17px;left:1px}.tippy-box[data-theme~=quarto][data-placement^=top]>.tippy-svg-arrow>svg{top:16px}.tippy-box[data-theme~=quarto][data-placement^=top]>.tippy-svg-arrow:after{top:17px}.tippy-box[data-theme~=quarto][data-placement^=bottom]>.tippy-arrow:before{border-bottom-color:#fff;bottom:16px}.tippy-box[data-theme~=quarto][data-placement^=bottom]>.tippy-arrow:after{border-bottom-color:#dee2e6;border-width:0 7px 7px;bottom:17px;left:1px}.tippy-box[data-theme~=quarto][data-placement^=bottom]>.tippy-svg-arrow>svg{bottom:15px}.tippy-box[data-theme~=quarto][data-placement^=bottom]>.tippy-svg-arrow:after{bottom:17px}.tippy-box[data-theme~=quarto][data-placement^=left]>.tippy-arrow:before{border-left-color:#fff}.tippy-box[data-theme~=quarto][data-placement^=left]>.tippy-arrow:after{border-left-color:#dee2e6;border-width:7px 0 7px 7px;left:17px;top:1px}.tippy-box[data-theme~=quarto][data-placement^=left]>.tippy-svg-arrow>svg{left:11px}.tippy-box[data-theme~=quarto][data-placement^=left]>.tippy-svg-arrow:after{left:12px}.tippy-box[data-theme~=quarto][data-placement^=right]>.tippy-arrow:before{border-right-color:#fff;right:16px}.tippy-box[data-theme~=quarto][data-placement^=right]>.tippy-arrow:after{border-width:7px 7px 7px 0;right:17px;top:1px;border-right-color:#dee2e6}.tippy-box[data-theme~=quarto][data-placement^=right]>.tippy-svg-arrow>svg{right:11px}.tippy-box[data-theme~=quarto][data-placement^=right]>.tippy-svg-arrow:after{right:12px}.tippy-box[data-theme~=quarto]>.tippy-svg-arrow{fill:#373a3c}.tippy-box[data-theme~=quarto]>.tippy-svg-arrow:after{background-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iNiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNMCA2czEuNzk2LS4wMTMgNC42Ny0zLjYxNUM1Ljg1MS45IDYuOTMuMDA2IDggMGMxLjA3LS4wMDYgMi4xNDguODg3IDMuMzQzIDIuMzg1QzE0LjIzMyA2LjAwNSAxNiA2IDE2IDZIMHoiIGZpbGw9InJnYmEoMCwgOCwgMTYsIDAuMikiLz48L3N2Zz4=);background-size:16px 6px;width:16px;height:6px}.top-right{position:absolute;top:1em;right:1em}.hidden{display:none !important}.zindex-bottom{z-index:-1 !important}.quarto-layout-panel{margin-bottom:1em}.quarto-layout-panel>figure{width:100%}.quarto-layout-panel>figure>figcaption,.quarto-layout-panel>.panel-caption{margin-top:10pt}.quarto-layout-panel>.table-caption{margin-top:0px}.table-caption p{margin-bottom:.5em}.quarto-layout-row{display:flex;flex-direction:row;align-items:flex-start}.quarto-layout-valign-top{align-items:flex-start}.quarto-layout-valign-bottom{align-items:flex-end}.quarto-layout-valign-center{align-items:center}.quarto-layout-cell{position:relative;margin-right:20px}.quarto-layout-cell:last-child{margin-right:0}.quarto-layout-cell figure,.quarto-layout-cell>p{margin:.2em}.quarto-layout-cell img{max-width:100%}.quarto-layout-cell .html-widget{width:100% !important}.quarto-layout-cell div figure p{margin:0}.quarto-layout-cell figure{display:inline-block;margin-inline-start:0;margin-inline-end:0}.quarto-layout-cell table{display:inline-table}.quarto-layout-cell-subref figcaption,figure .quarto-layout-row figure figcaption{text-align:center;font-style:italic}.quarto-figure{position:relative;margin-bottom:1em}.quarto-figure>figure{width:100%;margin-bottom:0}.quarto-figure-left>figure>p,.quarto-figure-left>figure>div{text-align:left}.quarto-figure-center>figure>p,.quarto-figure-center>figure>div{text-align:center}.quarto-figure-right>figure>p,.quarto-figure-right>figure>div{text-align:right}figure>p:empty{display:none}figure>p:first-child{margin-top:0;margin-bottom:0}figure>figcaption{margin-top:.5em}div[id^=tbl-]{position:relative}.quarto-figure>.anchorjs-link{position:absolute;top:.6em;right:.5em}div[id^=tbl-]>.anchorjs-link{position:absolute;top:.7em;right:.3em}.quarto-figure:hover>.anchorjs-link,div[id^=tbl-]:hover>.anchorjs-link,h2:hover>.anchorjs-link,.h2:hover>.anchorjs-link,h3:hover>.anchorjs-link,.h3:hover>.anchorjs-link,h4:hover>.anchorjs-link,.h4:hover>.anchorjs-link,h5:hover>.anchorjs-link,.h5:hover>.anchorjs-link,h6:hover>.anchorjs-link,.h6:hover>.anchorjs-link,.reveal-anchorjs-link>.anchorjs-link{opacity:1}#title-block-header{margin-block-end:1rem;position:relative;margin-top:-1px}#title-block-header .abstract{margin-block-start:1rem}#title-block-header .abstract .abstract-title{font-weight:600}#title-block-header a{text-decoration:none}#title-block-header .author,#title-block-header .date,#title-block-header .doi{margin-block-end:.2rem}#title-block-header .quarto-title-block>div{display:flex}#title-block-header .quarto-title-block>div>h1,#title-block-header .quarto-title-block>div>.h1{flex-grow:1}#title-block-header .quarto-title-block>div>button{flex-shrink:0;height:2.25rem;margin-top:0}@media(min-width: 992px){#title-block-header .quarto-title-block>div>button{margin-top:5px}}tr.header>th>p:last-of-type{margin-bottom:0px}table,.table{caption-side:top;margin-bottom:1.5rem}caption,.table-caption{padding-top:.5rem;padding-bottom:.5rem;text-align:center}.utterances{max-width:none;margin-left:-8px}iframe{margin-bottom:1em}details{margin-bottom:1em}details[show]{margin-bottom:0}details>summary{color:#6c757d}details>summary>p:only-child{display:inline}pre.sourceCode,code.sourceCode{position:relative}p code:not(.sourceCode){white-space:pre-wrap}code{white-space:pre}@media print{code{white-space:pre-wrap}}pre>code{display:block}pre>code.sourceCode{white-space:pre}pre>code.sourceCode>span>a:first-child::before{text-decoration:none}pre.code-overflow-wrap>code.sourceCode{white-space:pre-wrap}pre.code-overflow-scroll>code.sourceCode{white-space:pre}code a:any-link{color:inherit;text-decoration:none}code a:hover{color:inherit;text-decoration:underline}ul.task-list{padding-left:1em}[data-tippy-root]{display:inline-block}.tippy-content .footnote-back{display:none}.quarto-embedded-source-code{display:none}.quarto-unresolved-ref{font-weight:600}.quarto-cover-image{max-width:35%;float:right;margin-left:30px}.cell-output-display .widget-subarea{margin-bottom:1em}.cell-output-display:not(.no-overflow-x),.knitsql-table:not(.no-overflow-x){overflow-x:auto}.panel-input{margin-bottom:1em}.panel-input>div,.panel-input>div>div{display:inline-block;vertical-align:top;padding-right:12px}.panel-input>p:last-child{margin-bottom:0}.layout-sidebar{margin-bottom:1em}.layout-sidebar .tab-content{border:none}.tab-content>.page-columns.active{display:grid}div.sourceCode>iframe{width:100%;height:300px;margin-bottom:-0.5em}div.ansi-escaped-output{font-family:monospace;display:block}/*! +* +* ansi colors from IPython notebook's +* +*/.ansi-black-fg{color:#3e424d}.ansi-black-bg{background-color:#3e424d}.ansi-black-intense-fg{color:#282c36}.ansi-black-intense-bg{background-color:#282c36}.ansi-red-fg{color:#e75c58}.ansi-red-bg{background-color:#e75c58}.ansi-red-intense-fg{color:#b22b31}.ansi-red-intense-bg{background-color:#b22b31}.ansi-green-fg{color:#00a250}.ansi-green-bg{background-color:#00a250}.ansi-green-intense-fg{color:#007427}.ansi-green-intense-bg{background-color:#007427}.ansi-yellow-fg{color:#ddb62b}.ansi-yellow-bg{background-color:#ddb62b}.ansi-yellow-intense-fg{color:#b27d12}.ansi-yellow-intense-bg{background-color:#b27d12}.ansi-blue-fg{color:#208ffb}.ansi-blue-bg{background-color:#208ffb}.ansi-blue-intense-fg{color:#0065ca}.ansi-blue-intense-bg{background-color:#0065ca}.ansi-magenta-fg{color:#d160c4}.ansi-magenta-bg{background-color:#d160c4}.ansi-magenta-intense-fg{color:#a03196}.ansi-magenta-intense-bg{background-color:#a03196}.ansi-cyan-fg{color:#60c6c8}.ansi-cyan-bg{background-color:#60c6c8}.ansi-cyan-intense-fg{color:#258f8f}.ansi-cyan-intense-bg{background-color:#258f8f}.ansi-white-fg{color:#c5c1b4}.ansi-white-bg{background-color:#c5c1b4}.ansi-white-intense-fg{color:#a1a6b2}.ansi-white-intense-bg{background-color:#a1a6b2}.ansi-default-inverse-fg{color:#fff}.ansi-default-inverse-bg{background-color:#000}.ansi-bold{font-weight:bold}.ansi-underline{text-decoration:underline}:root{--quarto-body-bg: #fff;--quarto-body-color: #373a3c;--quarto-text-muted: #6c757d;--quarto-border-color: #dee2e6;--quarto-border-width: 1px;--quarto-border-radius: 0.25rem}table.gt_table{color:var(--quarto-body-color);font-size:1em;width:100%;background-color:rgba(0,0,0,0);border-top-width:inherit;border-bottom-width:inherit;border-color:var(--quarto-border-color)}table.gt_table th.gt_column_spanner_outer{color:var(--quarto-body-color);background-color:rgba(0,0,0,0);border-top-width:inherit;border-bottom-width:inherit;border-color:var(--quarto-border-color)}table.gt_table th.gt_col_heading{color:var(--quarto-body-color);font-weight:bold;background-color:rgba(0,0,0,0)}table.gt_table thead.gt_col_headings{border-bottom:1px solid currentColor;border-top-width:inherit;border-top-color:var(--quarto-border-color)}table.gt_table thead.gt_col_headings:not(:first-child){border-top-width:1px;border-top-color:var(--quarto-border-color)}table.gt_table td.gt_row{border-bottom-width:1px;border-bottom-color:var(--quarto-border-color);border-top-width:0px}table.gt_table tbody.gt_table_body{border-top-width:1px;border-bottom-width:1px;border-bottom-color:var(--quarto-border-color);border-top-color:currentColor}div.columns{display:initial;gap:initial}div.column{display:inline-block;overflow-x:initial;vertical-align:top;width:50%}.code-annotation-tip-content{word-wrap:break-word}.code-annotation-container-hidden{display:none !important}dl.code-annotation-container-grid{display:grid;grid-template-columns:min-content auto}dl.code-annotation-container-grid dt{grid-column:1}dl.code-annotation-container-grid dd{grid-column:2}pre.sourceCode.code-annotation-code{padding-right:0}code.sourceCode .code-annotation-anchor{z-index:100;position:absolute;right:.5em;left:inherit;background-color:rgba(0,0,0,0)}:root{--mermaid-bg-color: #fff;--mermaid-edge-color: #373a3c;--mermaid-node-fg-color: #373a3c;--mermaid-fg-color: #373a3c;--mermaid-fg-color--lighter: #4f5457;--mermaid-fg-color--lightest: #686d71;--mermaid-font-family: Source Sans Pro, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica Neue, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol;--mermaid-label-bg-color: #fff;--mermaid-label-fg-color: #2780e3;--mermaid-node-bg-color: rgba(39, 128, 227, 0.1);--mermaid-node-fg-color: #373a3c}@media print{:root{font-size:11pt}#quarto-sidebar,#TOC,.nav-page{display:none}.page-columns .content{grid-column-start:page-start}.fixed-top{position:relative}.panel-caption,.figure-caption,figcaption{color:#666}}.code-copy-button{position:absolute;top:0;right:0;border:0;margin-top:5px;margin-right:5px;background-color:rgba(0,0,0,0);z-index:3}.code-copy-button:focus{outline:none}.code-copy-button-tooltip{font-size:.75em}pre.sourceCode:hover>.code-copy-button>.bi::before{display:inline-block;height:1rem;width:1rem;content:"";vertical-align:-0.125em;background-image:url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="rgb(94, 94, 94)" viewBox="0 0 16 16"><path d="M4 1.5H3a2 2 0 0 0-2 2V14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3.5a2 2 0 0 0-2-2h-1v1h1a1 1 0 0 1 1 1V14a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V3.5a1 1 0 0 1 1-1h1v-1z"/><path d="M9.5 1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-1a.5.5 0 0 1 .5-.5h3zm-3-1A1.5 1.5 0 0 0 5 1.5v1A1.5 1.5 0 0 0 6.5 4h3A1.5 1.5 0 0 0 11 2.5v-1A1.5 1.5 0 0 0 9.5 0h-3z"/></svg>');background-repeat:no-repeat;background-size:1rem 1rem}pre.sourceCode:hover>.code-copy-button-checked>.bi::before{background-image:url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="rgb(94, 94, 94)" viewBox="0 0 16 16"><path d="M13.854 3.646a.5.5 0 0 1 0 .708l-7 7a.5.5 0 0 1-.708 0l-3.5-3.5a.5.5 0 1 1 .708-.708L6.5 10.293l6.646-6.647a.5.5 0 0 1 .708 0z"/></svg>')}pre.sourceCode:hover>.code-copy-button:hover>.bi::before{background-image:url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="rgb(71, 88, 171)" viewBox="0 0 16 16"><path d="M4 1.5H3a2 2 0 0 0-2 2V14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3.5a2 2 0 0 0-2-2h-1v1h1a1 1 0 0 1 1 1V14a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V3.5a1 1 0 0 1 1-1h1v-1z"/><path d="M9.5 1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-1a.5.5 0 0 1 .5-.5h3zm-3-1A1.5 1.5 0 0 0 5 1.5v1A1.5 1.5 0 0 0 6.5 4h3A1.5 1.5 0 0 0 11 2.5v-1A1.5 1.5 0 0 0 9.5 0h-3z"/></svg>')}pre.sourceCode:hover>.code-copy-button-checked:hover>.bi::before{background-image:url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="rgb(71, 88, 171)" viewBox="0 0 16 16"><path d="M13.854 3.646a.5.5 0 0 1 0 .708l-7 7a.5.5 0 0 1-.708 0l-3.5-3.5a.5.5 0 1 1 .708-.708L6.5 10.293l6.646-6.647a.5.5 0 0 1 .708 0z"/></svg>')}main ol ol,main ul ul,main ol ul,main ul ol{margin-bottom:1em}ul>li:not(:has(>p))>ul,ol>li:not(:has(>p))>ul,ul>li:not(:has(>p))>ol,ol>li:not(:has(>p))>ol{margin-bottom:0}ul>li:not(:has(>p))>ul>li:has(>p),ol>li:not(:has(>p))>ul>li:has(>p),ul>li:not(:has(>p))>ol>li:has(>p),ol>li:not(:has(>p))>ol>li:has(>p){margin-top:1rem}body{margin:0}main.page-columns>header>h1.title,main.page-columns>header>.title.h1{margin-bottom:0}@media(min-width: 992px){body .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset] 35px [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(500px, calc( 850px - 3em )) [body-content-end] 1.5em [body-end] 35px [body-end-outset] minmax(75px, 145px) [page-end-inset] 35px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.fullcontent:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset] 35px [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(500px, calc( 850px - 3em )) [body-content-end] 1.5em [body-end] 35px [body-end-outset] 35px [page-end-inset page-end] 5fr [screen-end-inset] 1.5em}body.slimcontent:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset] 35px [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(500px, calc( 850px - 3em )) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 200px) [page-end-inset] 35px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.listing:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc( 850px - 3em )) [body-content-end] 3em [body-end] 50px [body-end-outset] minmax(0px, 250px) [page-end-inset] minmax(50px, 100px) [page-end] 1fr [screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 35px [page-start-inset] minmax(0px, 175px) [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(450px, calc( 800px - 3em )) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 200px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 35px [page-start-inset] minmax(0px, 175px) [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(450px, calc( 800px - 3em )) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 200px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] minmax(25px, 50px) [page-start-inset] minmax(50px, 150px) [body-start-outset] minmax(25px, 50px) [body-start] 1.5em [body-content-start] minmax(500px, calc( 800px - 3em )) [body-content-end] 1.5em [body-end] minmax(25px, 50px) [body-end-outset] minmax(50px, 150px) [page-end-inset] minmax(25px, 50px) [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc( 1000px - 3em )) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(50px, 100px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc( 1000px - 3em )) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 50px [page-start-inset] minmax(50px, 150px) [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc( 800px - 3em )) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.slimcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(450px, calc( 750px - 3em )) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 200px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.listing .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start] minmax(50px, 100px) [page-start-inset] 50px [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(500px, calc( 1000px - 3em )) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(0px, 200px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.slimcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 50px [page-start-inset] minmax(50px, 150px) [body-start-outset] 50px [body-start] 1.5em [body-content-start] minmax(450px, calc( 750px - 3em )) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(50px, 150px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.listing .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] minmax(25px, 50px) [page-start-inset] minmax(50px, 150px) [body-start-outset] minmax(25px, 50px) [body-start] 1.5em [body-content-start] minmax(500px, calc( 800px - 3em )) [body-content-end] 1.5em [body-end] minmax(25px, 50px) [body-end-outset] minmax(50px, 150px) [page-end-inset] minmax(25px, 50px) [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}}@media(max-width: 991.98px){body .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset] 5fr [body-start] 1.5em [body-content-start] minmax(500px, calc( 800px - 3em )) [body-content-end] 1.5em [body-end] 35px [body-end-outset] minmax(75px, 145px) [page-end-inset] 35px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.fullcontent:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset] 5fr [body-start] 1.5em [body-content-start] minmax(500px, calc( 800px - 3em )) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.slimcontent:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset] 5fr [body-start] 1.5em [body-content-start] minmax(500px, calc( 800px - 3em )) [body-content-end] 1.5em [body-end] 35px [body-end-outset] minmax(75px, 145px) [page-end-inset] 35px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.listing:not(.floating):not(.docked) .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset] 5fr [body-start] 1.5em [body-content-start] minmax(500px, calc( 1250px - 3em )) [body-content-end body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 35px [page-start-inset] minmax(0px, 145px) [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(450px, calc( 800px - 3em )) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start] 35px [page-start-inset] minmax(0px, 145px) [body-start-outset] 35px [body-start] 1.5em [body-content-start] minmax(450px, calc( 800px - 3em )) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset body-start-outset body-start] 1.5em [body-content-start] minmax(500px, calc( 750px - 3em )) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(75px, 150px) [page-end-inset] 25px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(500px, calc( 750px - 3em )) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(25px, 50px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(500px, calc( 1000px - 3em )) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset body-start-outset body-start] 1em [body-content-start] minmax(500px, calc( 800px - 3em )) [body-content-end] 1.5em [body-end body-end-outset page-end-inset page-end] 4fr [screen-end-inset] 1.5em [screen-end]}body.docked.slimcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(500px, calc( 750px - 3em )) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(25px, 50px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.docked.listing .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(500px, calc( 750px - 3em )) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(25px, 50px) [page-end-inset] 50px [page-end] 5fr [screen-end-inset] 1.5em [screen-end]}body.floating.slimcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset body-start-outset body-start] 1em [body-content-start] minmax(500px, calc( 750px - 3em )) [body-content-end] 1.5em [body-end] 35px [body-end-outset] minmax(75px, 145px) [page-end-inset] 35px [page-end] 4fr [screen-end-inset] 1.5em [screen-end]}body.floating.listing .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset] 5fr [page-start page-start-inset body-start-outset body-start] 1em [body-content-start] minmax(500px, calc( 750px - 3em )) [body-content-end] 1.5em [body-end] 50px [body-end-outset] minmax(75px, 150px) [page-end-inset] 25px [page-end] 4fr [screen-end-inset] 1.5em [screen-end]}}@media(max-width: 767.98px){body .page-columns,body.fullcontent:not(.floating):not(.docked) .page-columns,body.slimcontent:not(.floating):not(.docked) .page-columns,body.docked .page-columns,body.docked.slimcontent .page-columns,body.docked.fullcontent .page-columns,body.floating .page-columns,body.floating.slimcontent .page-columns,body.floating.fullcontent .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(0px, 1fr) [body-content-end body-end body-end-outset page-end-inset page-end screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(0px, 1fr) [body-content-end body-end body-end-outset page-end-inset page-end screen-end-inset] 1.5em [screen-end]}body:not(.floating):not(.docked) .page-columns.toc-left .page-columns{display:grid;gap:0;grid-template-columns:[screen-start] 1.5em [screen-start-inset page-start page-start-inset body-start-outset body-start body-content-start] minmax(0px, 1fr) [body-content-end body-end body-end-outset page-end-inset page-end screen-end-inset] 1.5em [screen-end]}nav[role=doc-toc]{display:none}}body,.page-row-navigation{grid-template-rows:[page-top] max-content [contents-top] max-content [contents-bottom] max-content [page-bottom]}.page-rows-contents{grid-template-rows:[content-top] minmax(max-content, 1fr) [content-bottom] minmax(60px, max-content) [page-bottom]}.page-full{grid-column:screen-start/screen-end !important}.page-columns>*{grid-column:body-content-start/body-content-end}.page-columns.column-page>*{grid-column:page-start/page-end}.page-columns.column-page-left>*{grid-column:page-start/body-content-end}.page-columns.column-page-right>*{grid-column:body-content-start/page-end}.page-rows{grid-auto-rows:auto}.header{grid-column:screen-start/screen-end;grid-row:page-top/contents-top}#quarto-content{padding:0;grid-column:screen-start/screen-end;grid-row:contents-top/contents-bottom}body.floating .sidebar.sidebar-navigation{grid-column:page-start/body-start;grid-row:content-top/page-bottom}body.docked .sidebar.sidebar-navigation{grid-column:screen-start/body-start;grid-row:content-top/page-bottom}.sidebar.toc-left{grid-column:page-start/body-start;grid-row:content-top/page-bottom}.sidebar.margin-sidebar{grid-column:body-end/page-end;grid-row:content-top/page-bottom}.page-columns .content{grid-column:body-content-start/body-content-end;grid-row:content-top/content-bottom;align-content:flex-start}.page-columns .page-navigation{grid-column:body-content-start/body-content-end;grid-row:content-bottom/page-bottom}.page-columns .footer{grid-column:screen-start/screen-end;grid-row:contents-bottom/page-bottom}.page-columns .column-body{grid-column:body-content-start/body-content-end}.page-columns .column-body-fullbleed{grid-column:body-start/body-end}.page-columns .column-body-outset{grid-column:body-start-outset/body-end-outset;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-body-outset table{background:#fff}.page-columns .column-body-outset-left{grid-column:body-start-outset/body-content-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-body-outset-left table{background:#fff}.page-columns .column-body-outset-right{grid-column:body-content-start/body-end-outset;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-body-outset-right table{background:#fff}.page-columns .column-page{grid-column:page-start/page-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-page table{background:#fff}.page-columns .column-page-inset{grid-column:page-start-inset/page-end-inset;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-page-inset table{background:#fff}.page-columns .column-page-inset-left{grid-column:page-start-inset/body-content-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-page-inset-left table{background:#fff}.page-columns .column-page-inset-right{grid-column:body-content-start/page-end-inset;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-page-inset-right figcaption table{background:#fff}.page-columns .column-page-left{grid-column:page-start/body-content-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-page-left table{background:#fff}.page-columns .column-page-right{grid-column:body-content-start/page-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-page-right figcaption table{background:#fff}#quarto-content.page-columns #quarto-margin-sidebar,#quarto-content.page-columns #quarto-sidebar{z-index:1}@media(max-width: 991.98px){#quarto-content.page-columns #quarto-margin-sidebar.collapse,#quarto-content.page-columns #quarto-sidebar.collapse,#quarto-content.page-columns #quarto-margin-sidebar.collapsing,#quarto-content.page-columns #quarto-sidebar.collapsing{z-index:1055}}#quarto-content.page-columns main.column-page,#quarto-content.page-columns main.column-page-right,#quarto-content.page-columns main.column-page-left{z-index:0}.page-columns .column-screen-inset{grid-column:screen-start-inset/screen-end-inset;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen-inset table{background:#fff}.page-columns .column-screen-inset-left{grid-column:screen-start-inset/body-content-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen-inset-left table{background:#fff}.page-columns .column-screen-inset-right{grid-column:body-content-start/screen-end-inset;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen-inset-right table{background:#fff}.page-columns .column-screen{grid-column:screen-start/screen-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen table{background:#fff}.page-columns .column-screen-left{grid-column:screen-start/body-content-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen-left table{background:#fff}.page-columns .column-screen-right{grid-column:body-content-start/screen-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen-right table{background:#fff}.page-columns .column-screen-inset-shaded{grid-column:screen-start/screen-end;padding:1em;background:#f8f9fa;z-index:998;transform:translate3d(0, 0, 0);margin-bottom:1em}.zindex-content{z-index:998;transform:translate3d(0, 0, 0)}.zindex-modal{z-index:1055;transform:translate3d(0, 0, 0)}.zindex-over-content{z-index:999;transform:translate3d(0, 0, 0)}img.img-fluid.column-screen,img.img-fluid.column-screen-inset-shaded,img.img-fluid.column-screen-inset,img.img-fluid.column-screen-inset-left,img.img-fluid.column-screen-inset-right,img.img-fluid.column-screen-left,img.img-fluid.column-screen-right{width:100%}@media(min-width: 992px){.margin-caption,div.aside,aside,.column-margin{grid-column:body-end/page-end !important;z-index:998}.column-sidebar{grid-column:page-start/body-start !important;z-index:998}.column-leftmargin{grid-column:screen-start-inset/body-start !important;z-index:998}.no-row-height{height:1em;overflow:visible}}@media(max-width: 991.98px){.margin-caption,div.aside,aside,.column-margin{grid-column:body-end/page-end !important;z-index:998}.no-row-height{height:1em;overflow:visible}.page-columns.page-full{overflow:visible}.page-columns.toc-left .margin-caption,.page-columns.toc-left div.aside,.page-columns.toc-left aside,.page-columns.toc-left .column-margin{grid-column:body-content-start/body-content-end !important;z-index:998;transform:translate3d(0, 0, 0)}.page-columns.toc-left .no-row-height{height:initial;overflow:initial}}@media(max-width: 767.98px){.margin-caption,div.aside,aside,.column-margin{grid-column:body-content-start/body-content-end !important;z-index:998;transform:translate3d(0, 0, 0)}.no-row-height{height:initial;overflow:initial}#quarto-margin-sidebar{display:none}#quarto-sidebar-toc-left{display:none}.hidden-sm{display:none}}.panel-grid{display:grid;grid-template-rows:repeat(1, 1fr);grid-template-columns:repeat(24, 1fr);gap:1em}.panel-grid .g-col-1{grid-column:auto/span 1}.panel-grid .g-col-2{grid-column:auto/span 2}.panel-grid .g-col-3{grid-column:auto/span 3}.panel-grid .g-col-4{grid-column:auto/span 4}.panel-grid .g-col-5{grid-column:auto/span 5}.panel-grid .g-col-6{grid-column:auto/span 6}.panel-grid .g-col-7{grid-column:auto/span 7}.panel-grid .g-col-8{grid-column:auto/span 8}.panel-grid .g-col-9{grid-column:auto/span 9}.panel-grid .g-col-10{grid-column:auto/span 10}.panel-grid .g-col-11{grid-column:auto/span 11}.panel-grid .g-col-12{grid-column:auto/span 12}.panel-grid .g-col-13{grid-column:auto/span 13}.panel-grid .g-col-14{grid-column:auto/span 14}.panel-grid .g-col-15{grid-column:auto/span 15}.panel-grid .g-col-16{grid-column:auto/span 16}.panel-grid .g-col-17{grid-column:auto/span 17}.panel-grid .g-col-18{grid-column:auto/span 18}.panel-grid .g-col-19{grid-column:auto/span 19}.panel-grid .g-col-20{grid-column:auto/span 20}.panel-grid .g-col-21{grid-column:auto/span 21}.panel-grid .g-col-22{grid-column:auto/span 22}.panel-grid .g-col-23{grid-column:auto/span 23}.panel-grid .g-col-24{grid-column:auto/span 24}.panel-grid .g-start-1{grid-column-start:1}.panel-grid .g-start-2{grid-column-start:2}.panel-grid .g-start-3{grid-column-start:3}.panel-grid .g-start-4{grid-column-start:4}.panel-grid .g-start-5{grid-column-start:5}.panel-grid .g-start-6{grid-column-start:6}.panel-grid .g-start-7{grid-column-start:7}.panel-grid .g-start-8{grid-column-start:8}.panel-grid .g-start-9{grid-column-start:9}.panel-grid .g-start-10{grid-column-start:10}.panel-grid .g-start-11{grid-column-start:11}.panel-grid .g-start-12{grid-column-start:12}.panel-grid .g-start-13{grid-column-start:13}.panel-grid .g-start-14{grid-column-start:14}.panel-grid .g-start-15{grid-column-start:15}.panel-grid .g-start-16{grid-column-start:16}.panel-grid .g-start-17{grid-column-start:17}.panel-grid .g-start-18{grid-column-start:18}.panel-grid .g-start-19{grid-column-start:19}.panel-grid .g-start-20{grid-column-start:20}.panel-grid .g-start-21{grid-column-start:21}.panel-grid .g-start-22{grid-column-start:22}.panel-grid .g-start-23{grid-column-start:23}@media(min-width: 576px){.panel-grid .g-col-sm-1{grid-column:auto/span 1}.panel-grid .g-col-sm-2{grid-column:auto/span 2}.panel-grid .g-col-sm-3{grid-column:auto/span 3}.panel-grid .g-col-sm-4{grid-column:auto/span 4}.panel-grid .g-col-sm-5{grid-column:auto/span 5}.panel-grid .g-col-sm-6{grid-column:auto/span 6}.panel-grid .g-col-sm-7{grid-column:auto/span 7}.panel-grid .g-col-sm-8{grid-column:auto/span 8}.panel-grid .g-col-sm-9{grid-column:auto/span 9}.panel-grid .g-col-sm-10{grid-column:auto/span 10}.panel-grid .g-col-sm-11{grid-column:auto/span 11}.panel-grid .g-col-sm-12{grid-column:auto/span 12}.panel-grid .g-col-sm-13{grid-column:auto/span 13}.panel-grid .g-col-sm-14{grid-column:auto/span 14}.panel-grid .g-col-sm-15{grid-column:auto/span 15}.panel-grid .g-col-sm-16{grid-column:auto/span 16}.panel-grid .g-col-sm-17{grid-column:auto/span 17}.panel-grid .g-col-sm-18{grid-column:auto/span 18}.panel-grid .g-col-sm-19{grid-column:auto/span 19}.panel-grid .g-col-sm-20{grid-column:auto/span 20}.panel-grid .g-col-sm-21{grid-column:auto/span 21}.panel-grid .g-col-sm-22{grid-column:auto/span 22}.panel-grid .g-col-sm-23{grid-column:auto/span 23}.panel-grid .g-col-sm-24{grid-column:auto/span 24}.panel-grid .g-start-sm-1{grid-column-start:1}.panel-grid .g-start-sm-2{grid-column-start:2}.panel-grid .g-start-sm-3{grid-column-start:3}.panel-grid .g-start-sm-4{grid-column-start:4}.panel-grid .g-start-sm-5{grid-column-start:5}.panel-grid .g-start-sm-6{grid-column-start:6}.panel-grid .g-start-sm-7{grid-column-start:7}.panel-grid .g-start-sm-8{grid-column-start:8}.panel-grid .g-start-sm-9{grid-column-start:9}.panel-grid .g-start-sm-10{grid-column-start:10}.panel-grid .g-start-sm-11{grid-column-start:11}.panel-grid .g-start-sm-12{grid-column-start:12}.panel-grid .g-start-sm-13{grid-column-start:13}.panel-grid .g-start-sm-14{grid-column-start:14}.panel-grid .g-start-sm-15{grid-column-start:15}.panel-grid .g-start-sm-16{grid-column-start:16}.panel-grid .g-start-sm-17{grid-column-start:17}.panel-grid .g-start-sm-18{grid-column-start:18}.panel-grid .g-start-sm-19{grid-column-start:19}.panel-grid .g-start-sm-20{grid-column-start:20}.panel-grid .g-start-sm-21{grid-column-start:21}.panel-grid .g-start-sm-22{grid-column-start:22}.panel-grid .g-start-sm-23{grid-column-start:23}}@media(min-width: 768px){.panel-grid .g-col-md-1{grid-column:auto/span 1}.panel-grid .g-col-md-2{grid-column:auto/span 2}.panel-grid .g-col-md-3{grid-column:auto/span 3}.panel-grid .g-col-md-4{grid-column:auto/span 4}.panel-grid .g-col-md-5{grid-column:auto/span 5}.panel-grid .g-col-md-6{grid-column:auto/span 6}.panel-grid .g-col-md-7{grid-column:auto/span 7}.panel-grid .g-col-md-8{grid-column:auto/span 8}.panel-grid .g-col-md-9{grid-column:auto/span 9}.panel-grid .g-col-md-10{grid-column:auto/span 10}.panel-grid .g-col-md-11{grid-column:auto/span 11}.panel-grid .g-col-md-12{grid-column:auto/span 12}.panel-grid .g-col-md-13{grid-column:auto/span 13}.panel-grid .g-col-md-14{grid-column:auto/span 14}.panel-grid .g-col-md-15{grid-column:auto/span 15}.panel-grid .g-col-md-16{grid-column:auto/span 16}.panel-grid .g-col-md-17{grid-column:auto/span 17}.panel-grid .g-col-md-18{grid-column:auto/span 18}.panel-grid .g-col-md-19{grid-column:auto/span 19}.panel-grid .g-col-md-20{grid-column:auto/span 20}.panel-grid .g-col-md-21{grid-column:auto/span 21}.panel-grid .g-col-md-22{grid-column:auto/span 22}.panel-grid .g-col-md-23{grid-column:auto/span 23}.panel-grid .g-col-md-24{grid-column:auto/span 24}.panel-grid .g-start-md-1{grid-column-start:1}.panel-grid .g-start-md-2{grid-column-start:2}.panel-grid .g-start-md-3{grid-column-start:3}.panel-grid .g-start-md-4{grid-column-start:4}.panel-grid .g-start-md-5{grid-column-start:5}.panel-grid .g-start-md-6{grid-column-start:6}.panel-grid .g-start-md-7{grid-column-start:7}.panel-grid .g-start-md-8{grid-column-start:8}.panel-grid .g-start-md-9{grid-column-start:9}.panel-grid .g-start-md-10{grid-column-start:10}.panel-grid .g-start-md-11{grid-column-start:11}.panel-grid .g-start-md-12{grid-column-start:12}.panel-grid .g-start-md-13{grid-column-start:13}.panel-grid .g-start-md-14{grid-column-start:14}.panel-grid .g-start-md-15{grid-column-start:15}.panel-grid .g-start-md-16{grid-column-start:16}.panel-grid .g-start-md-17{grid-column-start:17}.panel-grid .g-start-md-18{grid-column-start:18}.panel-grid .g-start-md-19{grid-column-start:19}.panel-grid .g-start-md-20{grid-column-start:20}.panel-grid .g-start-md-21{grid-column-start:21}.panel-grid .g-start-md-22{grid-column-start:22}.panel-grid .g-start-md-23{grid-column-start:23}}@media(min-width: 992px){.panel-grid .g-col-lg-1{grid-column:auto/span 1}.panel-grid .g-col-lg-2{grid-column:auto/span 2}.panel-grid .g-col-lg-3{grid-column:auto/span 3}.panel-grid .g-col-lg-4{grid-column:auto/span 4}.panel-grid .g-col-lg-5{grid-column:auto/span 5}.panel-grid .g-col-lg-6{grid-column:auto/span 6}.panel-grid .g-col-lg-7{grid-column:auto/span 7}.panel-grid .g-col-lg-8{grid-column:auto/span 8}.panel-grid .g-col-lg-9{grid-column:auto/span 9}.panel-grid .g-col-lg-10{grid-column:auto/span 10}.panel-grid .g-col-lg-11{grid-column:auto/span 11}.panel-grid .g-col-lg-12{grid-column:auto/span 12}.panel-grid .g-col-lg-13{grid-column:auto/span 13}.panel-grid .g-col-lg-14{grid-column:auto/span 14}.panel-grid .g-col-lg-15{grid-column:auto/span 15}.panel-grid .g-col-lg-16{grid-column:auto/span 16}.panel-grid .g-col-lg-17{grid-column:auto/span 17}.panel-grid .g-col-lg-18{grid-column:auto/span 18}.panel-grid .g-col-lg-19{grid-column:auto/span 19}.panel-grid .g-col-lg-20{grid-column:auto/span 20}.panel-grid .g-col-lg-21{grid-column:auto/span 21}.panel-grid .g-col-lg-22{grid-column:auto/span 22}.panel-grid .g-col-lg-23{grid-column:auto/span 23}.panel-grid .g-col-lg-24{grid-column:auto/span 24}.panel-grid .g-start-lg-1{grid-column-start:1}.panel-grid .g-start-lg-2{grid-column-start:2}.panel-grid .g-start-lg-3{grid-column-start:3}.panel-grid .g-start-lg-4{grid-column-start:4}.panel-grid .g-start-lg-5{grid-column-start:5}.panel-grid .g-start-lg-6{grid-column-start:6}.panel-grid .g-start-lg-7{grid-column-start:7}.panel-grid .g-start-lg-8{grid-column-start:8}.panel-grid .g-start-lg-9{grid-column-start:9}.panel-grid .g-start-lg-10{grid-column-start:10}.panel-grid .g-start-lg-11{grid-column-start:11}.panel-grid .g-start-lg-12{grid-column-start:12}.panel-grid .g-start-lg-13{grid-column-start:13}.panel-grid .g-start-lg-14{grid-column-start:14}.panel-grid .g-start-lg-15{grid-column-start:15}.panel-grid .g-start-lg-16{grid-column-start:16}.panel-grid .g-start-lg-17{grid-column-start:17}.panel-grid .g-start-lg-18{grid-column-start:18}.panel-grid .g-start-lg-19{grid-column-start:19}.panel-grid .g-start-lg-20{grid-column-start:20}.panel-grid .g-start-lg-21{grid-column-start:21}.panel-grid .g-start-lg-22{grid-column-start:22}.panel-grid .g-start-lg-23{grid-column-start:23}}@media(min-width: 1200px){.panel-grid .g-col-xl-1{grid-column:auto/span 1}.panel-grid .g-col-xl-2{grid-column:auto/span 2}.panel-grid .g-col-xl-3{grid-column:auto/span 3}.panel-grid .g-col-xl-4{grid-column:auto/span 4}.panel-grid .g-col-xl-5{grid-column:auto/span 5}.panel-grid .g-col-xl-6{grid-column:auto/span 6}.panel-grid .g-col-xl-7{grid-column:auto/span 7}.panel-grid .g-col-xl-8{grid-column:auto/span 8}.panel-grid .g-col-xl-9{grid-column:auto/span 9}.panel-grid .g-col-xl-10{grid-column:auto/span 10}.panel-grid .g-col-xl-11{grid-column:auto/span 11}.panel-grid .g-col-xl-12{grid-column:auto/span 12}.panel-grid .g-col-xl-13{grid-column:auto/span 13}.panel-grid .g-col-xl-14{grid-column:auto/span 14}.panel-grid .g-col-xl-15{grid-column:auto/span 15}.panel-grid .g-col-xl-16{grid-column:auto/span 16}.panel-grid .g-col-xl-17{grid-column:auto/span 17}.panel-grid .g-col-xl-18{grid-column:auto/span 18}.panel-grid .g-col-xl-19{grid-column:auto/span 19}.panel-grid .g-col-xl-20{grid-column:auto/span 20}.panel-grid .g-col-xl-21{grid-column:auto/span 21}.panel-grid .g-col-xl-22{grid-column:auto/span 22}.panel-grid .g-col-xl-23{grid-column:auto/span 23}.panel-grid .g-col-xl-24{grid-column:auto/span 24}.panel-grid .g-start-xl-1{grid-column-start:1}.panel-grid .g-start-xl-2{grid-column-start:2}.panel-grid .g-start-xl-3{grid-column-start:3}.panel-grid .g-start-xl-4{grid-column-start:4}.panel-grid .g-start-xl-5{grid-column-start:5}.panel-grid .g-start-xl-6{grid-column-start:6}.panel-grid .g-start-xl-7{grid-column-start:7}.panel-grid .g-start-xl-8{grid-column-start:8}.panel-grid .g-start-xl-9{grid-column-start:9}.panel-grid .g-start-xl-10{grid-column-start:10}.panel-grid .g-start-xl-11{grid-column-start:11}.panel-grid .g-start-xl-12{grid-column-start:12}.panel-grid .g-start-xl-13{grid-column-start:13}.panel-grid .g-start-xl-14{grid-column-start:14}.panel-grid .g-start-xl-15{grid-column-start:15}.panel-grid .g-start-xl-16{grid-column-start:16}.panel-grid .g-start-xl-17{grid-column-start:17}.panel-grid .g-start-xl-18{grid-column-start:18}.panel-grid .g-start-xl-19{grid-column-start:19}.panel-grid .g-start-xl-20{grid-column-start:20}.panel-grid .g-start-xl-21{grid-column-start:21}.panel-grid .g-start-xl-22{grid-column-start:22}.panel-grid .g-start-xl-23{grid-column-start:23}}@media(min-width: 1400px){.panel-grid .g-col-xxl-1{grid-column:auto/span 1}.panel-grid .g-col-xxl-2{grid-column:auto/span 2}.panel-grid .g-col-xxl-3{grid-column:auto/span 3}.panel-grid .g-col-xxl-4{grid-column:auto/span 4}.panel-grid .g-col-xxl-5{grid-column:auto/span 5}.panel-grid .g-col-xxl-6{grid-column:auto/span 6}.panel-grid .g-col-xxl-7{grid-column:auto/span 7}.panel-grid .g-col-xxl-8{grid-column:auto/span 8}.panel-grid .g-col-xxl-9{grid-column:auto/span 9}.panel-grid .g-col-xxl-10{grid-column:auto/span 10}.panel-grid .g-col-xxl-11{grid-column:auto/span 11}.panel-grid .g-col-xxl-12{grid-column:auto/span 12}.panel-grid .g-col-xxl-13{grid-column:auto/span 13}.panel-grid .g-col-xxl-14{grid-column:auto/span 14}.panel-grid .g-col-xxl-15{grid-column:auto/span 15}.panel-grid .g-col-xxl-16{grid-column:auto/span 16}.panel-grid .g-col-xxl-17{grid-column:auto/span 17}.panel-grid .g-col-xxl-18{grid-column:auto/span 18}.panel-grid .g-col-xxl-19{grid-column:auto/span 19}.panel-grid .g-col-xxl-20{grid-column:auto/span 20}.panel-grid .g-col-xxl-21{grid-column:auto/span 21}.panel-grid .g-col-xxl-22{grid-column:auto/span 22}.panel-grid .g-col-xxl-23{grid-column:auto/span 23}.panel-grid .g-col-xxl-24{grid-column:auto/span 24}.panel-grid .g-start-xxl-1{grid-column-start:1}.panel-grid .g-start-xxl-2{grid-column-start:2}.panel-grid .g-start-xxl-3{grid-column-start:3}.panel-grid .g-start-xxl-4{grid-column-start:4}.panel-grid .g-start-xxl-5{grid-column-start:5}.panel-grid .g-start-xxl-6{grid-column-start:6}.panel-grid .g-start-xxl-7{grid-column-start:7}.panel-grid .g-start-xxl-8{grid-column-start:8}.panel-grid .g-start-xxl-9{grid-column-start:9}.panel-grid .g-start-xxl-10{grid-column-start:10}.panel-grid .g-start-xxl-11{grid-column-start:11}.panel-grid .g-start-xxl-12{grid-column-start:12}.panel-grid .g-start-xxl-13{grid-column-start:13}.panel-grid .g-start-xxl-14{grid-column-start:14}.panel-grid .g-start-xxl-15{grid-column-start:15}.panel-grid .g-start-xxl-16{grid-column-start:16}.panel-grid .g-start-xxl-17{grid-column-start:17}.panel-grid .g-start-xxl-18{grid-column-start:18}.panel-grid .g-start-xxl-19{grid-column-start:19}.panel-grid .g-start-xxl-20{grid-column-start:20}.panel-grid .g-start-xxl-21{grid-column-start:21}.panel-grid .g-start-xxl-22{grid-column-start:22}.panel-grid .g-start-xxl-23{grid-column-start:23}}main{margin-top:1em;margin-bottom:1em}h1,.h1,h2,.h2{opacity:.9;margin-top:2rem;margin-bottom:1rem;font-weight:600}h1.title,.title.h1{margin-top:0}h2,.h2{border-bottom:1px solid #dee2e6;padding-bottom:.5rem}h3,.h3{font-weight:600}h3,.h3,h4,.h4{opacity:.9;margin-top:1.5rem}h5,.h5,h6,.h6{opacity:.9}.header-section-number{color:#747a7f}.nav-link.active .header-section-number{color:inherit}mark,.mark{padding:0em}.panel-caption,caption,.figure-caption{font-size:.9rem}.panel-caption,.figure-caption,figcaption{color:#747a7f}.table-caption,caption{color:#373a3c}.quarto-layout-cell[data-ref-parent] caption{color:#747a7f}.column-margin figcaption,.margin-caption,div.aside,aside,.column-margin{color:#747a7f;font-size:.825rem}.panel-caption.margin-caption{text-align:inherit}.column-margin.column-container p{margin-bottom:0}.column-margin.column-container>*:not(.collapse){padding-top:.5em;padding-bottom:.5em;display:block}.column-margin.column-container>*.collapse:not(.show){display:none}@media(min-width: 768px){.column-margin.column-container .callout-margin-content:first-child{margin-top:4.5em}.column-margin.column-container .callout-margin-content-simple:first-child{margin-top:3.5em}}.margin-caption>*{padding-top:.5em;padding-bottom:.5em}@media(max-width: 767.98px){.quarto-layout-row{flex-direction:column}}.nav-tabs .nav-item{margin-top:1px;cursor:pointer}.tab-content{margin-top:0px;border-left:#dee2e6 1px solid;border-right:#dee2e6 1px solid;border-bottom:#dee2e6 1px solid;margin-left:0;padding:1em;margin-bottom:1em}@media(max-width: 767.98px){.layout-sidebar{margin-left:0;margin-right:0}}.panel-sidebar,.panel-sidebar .form-control,.panel-input,.panel-input .form-control,.selectize-dropdown{font-size:.9rem}.panel-sidebar .form-control,.panel-input .form-control{padding-top:.1rem}.tab-pane div.sourceCode{margin-top:0px}.tab-pane>p{padding-top:1em}.tab-content>.tab-pane:not(.active){display:none !important}div.sourceCode{background-color:rgba(233,236,239,.65);border:1px solid rgba(233,236,239,.65);border-radius:.25rem}pre.sourceCode{background-color:rgba(0,0,0,0)}pre.sourceCode{border:none;font-size:.875em;overflow:visible !important;padding:.4em}.callout pre.sourceCode{padding-left:0}div.sourceCode{overflow-y:hidden}.callout div.sourceCode{margin-left:initial}.blockquote{font-size:inherit;padding-left:1rem;padding-right:1.5rem;color:#747a7f}.blockquote h1:first-child,.blockquote .h1:first-child,.blockquote h2:first-child,.blockquote .h2:first-child,.blockquote h3:first-child,.blockquote .h3:first-child,.blockquote h4:first-child,.blockquote .h4:first-child,.blockquote h5:first-child,.blockquote .h5:first-child{margin-top:0}pre{background-color:initial;padding:initial;border:initial}p code:not(.sourceCode),li code:not(.sourceCode),td code:not(.sourceCode){background-color:#f7f7f7;padding:.2em}nav p code:not(.sourceCode),nav li code:not(.sourceCode),nav td code:not(.sourceCode){background-color:rgba(0,0,0,0);padding:0}td code:not(.sourceCode){white-space:pre-wrap}#quarto-embedded-source-code-modal>.modal-dialog{max-width:1000px;padding-left:1.75rem;padding-right:1.75rem}#quarto-embedded-source-code-modal>.modal-dialog>.modal-content>.modal-body{padding:0}#quarto-embedded-source-code-modal>.modal-dialog>.modal-content>.modal-body div.sourceCode{margin:0;padding:.2rem .2rem;border-radius:0px;border:none}#quarto-embedded-source-code-modal>.modal-dialog>.modal-content>.modal-header{padding:.7rem}.code-tools-button{font-size:1rem;padding:.15rem .15rem;margin-left:5px;color:#6c757d;background-color:rgba(0,0,0,0);transition:initial;cursor:pointer}.code-tools-button>.bi::before{display:inline-block;height:1rem;width:1rem;content:"";vertical-align:-0.125em;background-image:url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="rgb(108, 117, 125)" viewBox="0 0 16 16"><path d="M10.478 1.647a.5.5 0 1 0-.956-.294l-4 13a.5.5 0 0 0 .956.294l4-13zM4.854 4.146a.5.5 0 0 1 0 .708L1.707 8l3.147 3.146a.5.5 0 0 1-.708.708l-3.5-3.5a.5.5 0 0 1 0-.708l3.5-3.5a.5.5 0 0 1 .708 0zm6.292 0a.5.5 0 0 0 0 .708L14.293 8l-3.147 3.146a.5.5 0 0 0 .708.708l3.5-3.5a.5.5 0 0 0 0-.708l-3.5-3.5a.5.5 0 0 0-.708 0z"/></svg>');background-repeat:no-repeat;background-size:1rem 1rem}.code-tools-button:hover>.bi::before{background-image:url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="rgb(55, 58, 60)" viewBox="0 0 16 16"><path d="M10.478 1.647a.5.5 0 1 0-.956-.294l-4 13a.5.5 0 0 0 .956.294l4-13zM4.854 4.146a.5.5 0 0 1 0 .708L1.707 8l3.147 3.146a.5.5 0 0 1-.708.708l-3.5-3.5a.5.5 0 0 1 0-.708l3.5-3.5a.5.5 0 0 1 .708 0zm6.292 0a.5.5 0 0 0 0 .708L14.293 8l-3.147 3.146a.5.5 0 0 0 .708.708l3.5-3.5a.5.5 0 0 0 0-.708l-3.5-3.5a.5.5 0 0 0-.708 0z"/></svg>')}#quarto-embedded-source-code-modal .code-copy-button>.bi::before{background-image:url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="rgb(108, 117, 125)" viewBox="0 0 16 16"><path d="M4 1.5H3a2 2 0 0 0-2 2V14a2 2 0 0 0 2 2h10a2 2 0 0 0 2-2V3.5a2 2 0 0 0-2-2h-1v1h1a1 1 0 0 1 1 1V14a1 1 0 0 1-1 1H3a1 1 0 0 1-1-1V3.5a1 1 0 0 1 1-1h1v-1z"/><path d="M9.5 1a.5.5 0 0 1 .5.5v1a.5.5 0 0 1-.5.5h-3a.5.5 0 0 1-.5-.5v-1a.5.5 0 0 1 .5-.5h3zm-3-1A1.5 1.5 0 0 0 5 1.5v1A1.5 1.5 0 0 0 6.5 4h3A1.5 1.5 0 0 0 11 2.5v-1A1.5 1.5 0 0 0 9.5 0h-3z"/></svg>')}#quarto-embedded-source-code-modal .code-copy-button-checked>.bi::before{background-image:url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="rgb(108, 117, 125)" viewBox="0 0 16 16"><path d="M13.854 3.646a.5.5 0 0 1 0 .708l-7 7a.5.5 0 0 1-.708 0l-3.5-3.5a.5.5 0 1 1 .708-.708L6.5 10.293l6.646-6.647a.5.5 0 0 1 .708 0z"/></svg>')}.sidebar{will-change:top;transition:top 200ms linear;position:sticky;overflow-y:auto;padding-top:1.2em;max-height:100vh}.sidebar.toc-left,.sidebar.margin-sidebar{top:0px;padding-top:1em}.sidebar.toc-left>*,.sidebar.margin-sidebar>*{padding-top:.5em}.sidebar.quarto-banner-title-block-sidebar>*{padding-top:1.65em}figure .quarto-notebook-link{margin-top:.5em}.quarto-notebook-link{font-size:.75em;color:#6c757d;margin-bottom:1em;text-decoration:none;display:block}.quarto-notebook-link:hover{text-decoration:underline;color:#2780e3}.quarto-notebook-link::before{display:inline-block;height:.75rem;width:.75rem;margin-bottom:0em;margin-right:.25em;content:"";vertical-align:-0.125em;background-image:url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="rgb(108, 117, 125)" class="bi bi-journal-code" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.646 5.646a.5.5 0 0 1 .708 0l2 2a.5.5 0 0 1 0 .708l-2 2a.5.5 0 0 1-.708-.708L10.293 8 8.646 6.354a.5.5 0 0 1 0-.708zm-1.292 0a.5.5 0 0 0-.708 0l-2 2a.5.5 0 0 0 0 .708l2 2a.5.5 0 0 0 .708-.708L5.707 8l1.647-1.646a.5.5 0 0 0 0-.708z"/><path d="M3 0h10a2 2 0 0 1 2 2v12a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2v-1h1v1a1 1 0 0 0 1 1h10a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1H3a1 1 0 0 0-1 1v1H1V2a2 2 0 0 1 2-2z"/><path d="M1 5v-.5a.5.5 0 0 1 1 0V5h.5a.5.5 0 0 1 0 1h-2a.5.5 0 0 1 0-1H1zm0 3v-.5a.5.5 0 0 1 1 0V8h.5a.5.5 0 0 1 0 1h-2a.5.5 0 0 1 0-1H1zm0 3v-.5a.5.5 0 0 1 1 0v.5h.5a.5.5 0 0 1 0 1h-2a.5.5 0 0 1 0-1H1z"/></svg>');background-repeat:no-repeat;background-size:.75rem .75rem}.quarto-alternate-notebooks i.bi,.quarto-alternate-formats i.bi{margin-right:.4em}.quarto-notebook .cell-container{display:flex}.quarto-notebook .cell-container .cell{flex-grow:4}.quarto-notebook .cell-container .cell-decorator{padding-top:1.5em;padding-right:1em;text-align:right}.quarto-notebook h2,.quarto-notebook .h2{border-bottom:none}.sidebar .quarto-alternate-formats a,.sidebar .quarto-alternate-notebooks a{text-decoration:none}.sidebar .quarto-alternate-formats a:hover,.sidebar .quarto-alternate-notebooks a:hover{color:#2780e3}.sidebar .quarto-alternate-notebooks h2,.sidebar .quarto-alternate-notebooks .h2,.sidebar .quarto-alternate-formats h2,.sidebar .quarto-alternate-formats .h2,.sidebar nav[role=doc-toc]>h2,.sidebar nav[role=doc-toc]>.h2{font-size:.875rem;font-weight:400;margin-bottom:.5rem;margin-top:.3rem;font-family:inherit;border-bottom:0;padding-bottom:0;padding-top:0px}.sidebar .quarto-alternate-notebooks h2,.sidebar .quarto-alternate-notebooks .h2,.sidebar .quarto-alternate-formats h2,.sidebar .quarto-alternate-formats .h2{margin-top:1rem}.sidebar nav[role=doc-toc]>ul a{border-left:1px solid #e9ecef;padding-left:.6rem}.sidebar .quarto-alternate-notebooks h2>ul a,.sidebar .quarto-alternate-notebooks .h2>ul a,.sidebar .quarto-alternate-formats h2>ul a,.sidebar .quarto-alternate-formats .h2>ul a{border-left:none;padding-left:.6rem}.sidebar .quarto-alternate-notebooks ul a:empty,.sidebar .quarto-alternate-formats ul a:empty,.sidebar nav[role=doc-toc]>ul a:empty{display:none}.sidebar .quarto-alternate-notebooks ul,.sidebar .quarto-alternate-formats ul,.sidebar nav[role=doc-toc] ul{padding-left:0;list-style:none;font-size:.875rem;font-weight:300}.sidebar .quarto-alternate-notebooks ul li a,.sidebar .quarto-alternate-formats ul li a,.sidebar nav[role=doc-toc]>ul li a{line-height:1.1rem;padding-bottom:.2rem;padding-top:.2rem;color:inherit}.sidebar nav[role=doc-toc] ul>li>ul>li>a{padding-left:1.2em}.sidebar nav[role=doc-toc] ul>li>ul>li>ul>li>a{padding-left:2.4em}.sidebar nav[role=doc-toc] ul>li>ul>li>ul>li>ul>li>a{padding-left:3.6em}.sidebar nav[role=doc-toc] ul>li>ul>li>ul>li>ul>li>ul>li>a{padding-left:4.8em}.sidebar nav[role=doc-toc] ul>li>ul>li>ul>li>ul>li>ul>li>ul>li>a{padding-left:6em}.sidebar nav[role=doc-toc] ul>li>a.active,.sidebar nav[role=doc-toc] ul>li>ul>li>a.active{border-left:1px solid #2780e3;color:#2780e3 !important}.sidebar nav[role=doc-toc] ul>li>a:hover,.sidebar nav[role=doc-toc] ul>li>ul>li>a:hover{color:#2780e3 !important}kbd,.kbd{color:#373a3c;background-color:#f8f9fa;border:1px solid;border-radius:5px;border-color:#dee2e6}div.hanging-indent{margin-left:1em;text-indent:-1em}.citation a,.footnote-ref{text-decoration:none}.footnotes ol{padding-left:1em}.tippy-content>*{margin-bottom:.7em}.tippy-content>*:last-child{margin-bottom:0}.table a{word-break:break-word}.table>thead{border-top-width:1px;border-top-color:#dee2e6;border-bottom:1px solid #b6babc}.callout{margin-top:1.25rem;margin-bottom:1.25rem;border-radius:.25rem;overflow-wrap:break-word}.callout .callout-title-container{overflow-wrap:anywhere}.callout.callout-style-simple{padding:.4em .7em;border-left:5px solid;border-right:1px solid #dee2e6;border-top:1px solid #dee2e6;border-bottom:1px solid #dee2e6}.callout.callout-style-default{border-left:5px solid;border-right:1px solid #dee2e6;border-top:1px solid #dee2e6;border-bottom:1px solid #dee2e6}.callout .callout-body-container{flex-grow:1}.callout.callout-style-simple .callout-body{font-size:.9rem;font-weight:400}.callout.callout-style-default .callout-body{font-size:.9rem;font-weight:400}.callout.callout-titled .callout-body{margin-top:.2em}.callout:not(.no-icon).callout-titled.callout-style-simple .callout-body{padding-left:1.6em}.callout.callout-titled>.callout-header{padding-top:.2em;margin-bottom:-0.2em}.callout.callout-style-simple>div.callout-header{border-bottom:none;font-size:.9rem;font-weight:600;opacity:75%}.callout.callout-style-default>div.callout-header{border-bottom:none;font-weight:600;opacity:85%;font-size:.9rem;padding-left:.5em;padding-right:.5em}.callout.callout-style-default div.callout-body{padding-left:.5em;padding-right:.5em}.callout.callout-style-default div.callout-body>:first-child{margin-top:.5em}.callout>div.callout-header[data-bs-toggle=collapse]{cursor:pointer}.callout.callout-style-default .callout-header[aria-expanded=false],.callout.callout-style-default .callout-header[aria-expanded=true]{padding-top:0px;margin-bottom:0px;align-items:center}.callout.callout-titled .callout-body>:last-child:not(.sourceCode),.callout.callout-titled .callout-body>div>:last-child:not(.sourceCode){margin-bottom:.5rem}.callout:not(.callout-titled) .callout-body>:first-child,.callout:not(.callout-titled) .callout-body>div>:first-child{margin-top:.25rem}.callout:not(.callout-titled) .callout-body>:last-child,.callout:not(.callout-titled) .callout-body>div>:last-child{margin-bottom:.2rem}.callout.callout-style-simple .callout-icon::before,.callout.callout-style-simple .callout-toggle::before{height:1rem;width:1rem;display:inline-block;content:"";background-repeat:no-repeat;background-size:1rem 1rem}.callout.callout-style-default .callout-icon::before,.callout.callout-style-default .callout-toggle::before{height:.9rem;width:.9rem;display:inline-block;content:"";background-repeat:no-repeat;background-size:.9rem .9rem}.callout.callout-style-default .callout-toggle::before{margin-top:5px}.callout .callout-btn-toggle .callout-toggle::before{transition:transform .2s linear}.callout .callout-header[aria-expanded=false] .callout-toggle::before{transform:rotate(-90deg)}.callout .callout-header[aria-expanded=true] .callout-toggle::before{transform:none}.callout.callout-style-simple:not(.no-icon) div.callout-icon-container{padding-top:.2em;padding-right:.55em}.callout.callout-style-default:not(.no-icon) div.callout-icon-container{padding-top:.1em;padding-right:.35em}.callout.callout-style-default:not(.no-icon) div.callout-title-container{margin-top:-1px}.callout.callout-style-default.callout-caution:not(.no-icon) div.callout-icon-container{padding-top:.3em;padding-right:.35em}.callout>.callout-body>.callout-icon-container>.no-icon,.callout>.callout-header>.callout-icon-container>.no-icon{display:none}div.callout.callout{border-left-color:#6c757d}div.callout.callout-style-default>.callout-header{background-color:#6c757d}div.callout-note.callout{border-left-color:#2780e3}div.callout-note.callout-style-default>.callout-header{background-color:#e9f2fc}div.callout-note:not(.callout-titled) .callout-icon::before{background-image:url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" style="fill: %232373cc" class="bi bi-info-circle" viewBox="0 0 16 16"><path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"/><path d="m8.93 6.588-2.29.287-.082.38.45.083c.294.07.352.176.288.469l-.738 3.468c-.194.897.105 1.319.808 1.319.545 0 1.178-.252 1.465-.598l.088-.416c-.2.176-.492.246-.686.246-.275 0-.375-.193-.304-.533L8.93 6.588zM9 4.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0z"/></svg>');}div.callout-note.callout-titled .callout-icon::before{background-image:url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" style="fill: %232373cc" class="bi bi-info-circle" viewBox="0 0 16 16"><path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"/><path d="m8.93 6.588-2.29.287-.082.38.45.083c.294.07.352.176.288.469l-.738 3.468c-.194.897.105 1.319.808 1.319.545 0 1.178-.252 1.465-.598l.088-.416c-.2.176-.492.246-.686.246-.275 0-.375-.193-.304-.533L8.93 6.588zM9 4.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0z"/></svg>');}div.callout-note .callout-toggle::before{background-image:url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="rgb(55, 58, 60)" class="bi bi-chevron-down" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z"/></svg>')}div.callout-tip.callout{border-left-color:#3fb618}div.callout-tip.callout-style-default>.callout-header{background-color:#ecf8e8}div.callout-tip:not(.callout-titled) .callout-icon::before{background-image:url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" style="fill: %2339a416" class="bi bi-lightbulb" viewBox="0 0 16 16"><path d="M2 6a6 6 0 1 1 10.174 4.31c-.203.196-.359.4-.453.619l-.762 1.769A.5.5 0 0 1 10.5 13a.5.5 0 0 1 0 1 .5.5 0 0 1 0 1l-.224.447a1 1 0 0 1-.894.553H6.618a1 1 0 0 1-.894-.553L5.5 15a.5.5 0 0 1 0-1 .5.5 0 0 1 0-1 .5.5 0 0 1-.46-.302l-.761-1.77a1.964 1.964 0 0 0-.453-.618A5.984 5.984 0 0 1 2 6zm6-5a5 5 0 0 0-3.479 8.592c.263.254.514.564.676.941L5.83 12h4.342l.632-1.467c.162-.377.413-.687.676-.941A5 5 0 0 0 8 1z"/></svg>');}div.callout-tip.callout-titled .callout-icon::before{background-image:url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" style="fill: %2339a416" class="bi bi-lightbulb" viewBox="0 0 16 16"><path d="M2 6a6 6 0 1 1 10.174 4.31c-.203.196-.359.4-.453.619l-.762 1.769A.5.5 0 0 1 10.5 13a.5.5 0 0 1 0 1 .5.5 0 0 1 0 1l-.224.447a1 1 0 0 1-.894.553H6.618a1 1 0 0 1-.894-.553L5.5 15a.5.5 0 0 1 0-1 .5.5 0 0 1 0-1 .5.5 0 0 1-.46-.302l-.761-1.77a1.964 1.964 0 0 0-.453-.618A5.984 5.984 0 0 1 2 6zm6-5a5 5 0 0 0-3.479 8.592c.263.254.514.564.676.941L5.83 12h4.342l.632-1.467c.162-.377.413-.687.676-.941A5 5 0 0 0 8 1z"/></svg>');}div.callout-tip .callout-toggle::before{background-image:url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="rgb(55, 58, 60)" class="bi bi-chevron-down" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z"/></svg>')}div.callout-warning.callout{border-left-color:#ff7518}div.callout-warning.callout-style-default>.callout-header{background-color:#fff1e8}div.callout-warning:not(.callout-titled) .callout-icon::before{background-image:url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" style="fill: %23e66916" class="bi bi-exclamation-triangle" viewBox="0 0 16 16"><path d="M7.938 2.016A.13.13 0 0 1 8.002 2a.13.13 0 0 1 .063.016.146.146 0 0 1 .054.057l6.857 11.667c.036.06.035.124.002.183a.163.163 0 0 1-.054.06.116.116 0 0 1-.066.017H1.146a.115.115 0 0 1-.066-.017.163.163 0 0 1-.054-.06.176.176 0 0 1 .002-.183L7.884 2.073a.147.147 0 0 1 .054-.057zm1.044-.45a1.13 1.13 0 0 0-1.96 0L.165 13.233c-.457.778.091 1.767.98 1.767h13.713c.889 0 1.438-.99.98-1.767L8.982 1.566z"/><path d="M7.002 12a1 1 0 1 1 2 0 1 1 0 0 1-2 0zM7.1 5.995a.905.905 0 1 1 1.8 0l-.35 3.507a.552.552 0 0 1-1.1 0L7.1 5.995z"/></svg>');}div.callout-warning.callout-titled .callout-icon::before{background-image:url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" style="fill: %23e66916" class="bi bi-exclamation-triangle" viewBox="0 0 16 16"><path d="M7.938 2.016A.13.13 0 0 1 8.002 2a.13.13 0 0 1 .063.016.146.146 0 0 1 .054.057l6.857 11.667c.036.06.035.124.002.183a.163.163 0 0 1-.054.06.116.116 0 0 1-.066.017H1.146a.115.115 0 0 1-.066-.017.163.163 0 0 1-.054-.06.176.176 0 0 1 .002-.183L7.884 2.073a.147.147 0 0 1 .054-.057zm1.044-.45a1.13 1.13 0 0 0-1.96 0L.165 13.233c-.457.778.091 1.767.98 1.767h13.713c.889 0 1.438-.99.98-1.767L8.982 1.566z"/><path d="M7.002 12a1 1 0 1 1 2 0 1 1 0 0 1-2 0zM7.1 5.995a.905.905 0 1 1 1.8 0l-.35 3.507a.552.552 0 0 1-1.1 0L7.1 5.995z"/></svg>');}div.callout-warning .callout-toggle::before{background-image:url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="rgb(55, 58, 60)" class="bi bi-chevron-down" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z"/></svg>')}div.callout-caution.callout{border-left-color:#f0ad4e}div.callout-caution.callout-style-default>.callout-header{background-color:#fef7ed}div.callout-caution:not(.callout-titled) .callout-icon::before{background-image:url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" style="fill: %23d89c46" class="bi bi-cone-striped" viewBox="0 0 16 16"><path d="M9.97 4.88l.953 3.811C10.158 8.878 9.14 9 8 9c-1.14 0-2.159-.122-2.923-.309L6.03 4.88C6.635 4.957 7.3 5 8 5s1.365-.043 1.97-.12zm-.245-.978L8.97.88C8.718-.13 7.282-.13 7.03.88L6.274 3.9C6.8 3.965 7.382 4 8 4c.618 0 1.2-.036 1.725-.098zm4.396 8.613a.5.5 0 0 1 .037.96l-6 2a.5.5 0 0 1-.316 0l-6-2a.5.5 0 0 1 .037-.96l2.391-.598.565-2.257c.862.212 1.964.339 3.165.339s2.303-.127 3.165-.339l.565 2.257 2.391.598z"/></svg>');}div.callout-caution.callout-titled .callout-icon::before{background-image:url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" style="fill: %23d89c46" class="bi bi-cone-striped" viewBox="0 0 16 16"><path d="M9.97 4.88l.953 3.811C10.158 8.878 9.14 9 8 9c-1.14 0-2.159-.122-2.923-.309L6.03 4.88C6.635 4.957 7.3 5 8 5s1.365-.043 1.97-.12zm-.245-.978L8.97.88C8.718-.13 7.282-.13 7.03.88L6.274 3.9C6.8 3.965 7.382 4 8 4c.618 0 1.2-.036 1.725-.098zm4.396 8.613a.5.5 0 0 1 .037.96l-6 2a.5.5 0 0 1-.316 0l-6-2a.5.5 0 0 1 .037-.96l2.391-.598.565-2.257c.862.212 1.964.339 3.165.339s2.303-.127 3.165-.339l.565 2.257 2.391.598z"/></svg>');}div.callout-caution .callout-toggle::before{background-image:url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="rgb(55, 58, 60)" class="bi bi-chevron-down" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z"/></svg>')}div.callout-important.callout{border-left-color:#ff0039}div.callout-important.callout-style-default>.callout-header{background-color:#ffe6eb}div.callout-important:not(.callout-titled) .callout-icon::before{background-image:url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" style="fill: %23e60033" class="bi bi-exclamation-circle" viewBox="0 0 16 16"><path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"/><path d="M7.002 11a1 1 0 1 1 2 0 1 1 0 0 1-2 0zM7.1 4.995a.905.905 0 1 1 1.8 0l-.35 3.507a.552.552 0 0 1-1.1 0L7.1 4.995z"/></svg>');}div.callout-important.callout-titled .callout-icon::before{background-image:url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" style="fill: %23e60033" class="bi bi-exclamation-circle" viewBox="0 0 16 16"><path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z"/><path d="M7.002 11a1 1 0 1 1 2 0 1 1 0 0 1-2 0zM7.1 4.995a.905.905 0 1 1 1.8 0l-.35 3.507a.552.552 0 0 1-1.1 0L7.1 4.995z"/></svg>');}div.callout-important .callout-toggle::before{background-image:url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="rgb(55, 58, 60)" class="bi bi-chevron-down" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M1.646 4.646a.5.5 0 0 1 .708 0L8 10.293l5.646-5.647a.5.5 0 0 1 .708.708l-6 6a.5.5 0 0 1-.708 0l-6-6a.5.5 0 0 1 0-.708z"/></svg>')}.quarto-toggle-container{display:flex;align-items:center}.quarto-reader-toggle .bi::before,.quarto-color-scheme-toggle .bi::before{display:inline-block;height:1rem;width:1rem;content:"";background-repeat:no-repeat;background-size:1rem 1rem}.sidebar-navigation{padding-left:20px}.navbar .quarto-color-scheme-toggle:not(.alternate) .bi::before{background-image:url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="rgba(253, 254, 255, 1)" class="bi bi-toggle-off" viewBox="0 0 16 16"><path d="M11 4a4 4 0 0 1 0 8H8a4.992 4.992 0 0 0 2-4 4.992 4.992 0 0 0-2-4h3zm-6 8a4 4 0 1 1 0-8 4 4 0 0 1 0 8zM0 8a5 5 0 0 0 5 5h6a5 5 0 0 0 0-10H5a5 5 0 0 0-5 5z"/></svg>')}.navbar .quarto-color-scheme-toggle.alternate .bi::before{background-image:url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="rgba(253, 254, 255, 1)" class="bi bi-toggle-on" viewBox="0 0 16 16"><path d="M5 3a5 5 0 0 0 0 10h6a5 5 0 0 0 0-10H5zm6 9a4 4 0 1 1 0-8 4 4 0 0 1 0 8z"/></svg>')}.sidebar-navigation .quarto-color-scheme-toggle:not(.alternate) .bi::before{background-image:url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="rgba(79, 84, 87, 1)" class="bi bi-toggle-off" viewBox="0 0 16 16"><path d="M11 4a4 4 0 0 1 0 8H8a4.992 4.992 0 0 0 2-4 4.992 4.992 0 0 0-2-4h3zm-6 8a4 4 0 1 1 0-8 4 4 0 0 1 0 8zM0 8a5 5 0 0 0 5 5h6a5 5 0 0 0 0-10H5a5 5 0 0 0-5 5z"/></svg>')}.sidebar-navigation .quarto-color-scheme-toggle.alternate .bi::before{background-image:url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="rgba(79, 84, 87, 1)" class="bi bi-toggle-on" viewBox="0 0 16 16"><path d="M5 3a5 5 0 0 0 0 10h6a5 5 0 0 0 0-10H5zm6 9a4 4 0 1 1 0-8 4 4 0 0 1 0 8z"/></svg>')}.quarto-sidebar-toggle{border-color:#dee2e6;border-bottom-left-radius:.25rem;border-bottom-right-radius:.25rem;border-style:solid;border-width:1px;overflow:hidden;border-top-width:0px;padding-top:0px !important}.quarto-sidebar-toggle-title{cursor:pointer;padding-bottom:2px;margin-left:.25em;text-align:center;font-weight:400;font-size:.775em}#quarto-content .quarto-sidebar-toggle{background:#fafafa}#quarto-content .quarto-sidebar-toggle-title{color:#373a3c}.quarto-sidebar-toggle-icon{color:#dee2e6;margin-right:.5em;float:right;transition:transform .2s ease}.quarto-sidebar-toggle-icon::before{padding-top:5px}.quarto-sidebar-toggle.expanded .quarto-sidebar-toggle-icon{transform:rotate(-180deg)}.quarto-sidebar-toggle.expanded .quarto-sidebar-toggle-title{border-bottom:solid #dee2e6 1px}.quarto-sidebar-toggle-contents{background-color:#fff;padding-right:10px;padding-left:10px;margin-top:0px !important;transition:max-height .5s ease}.quarto-sidebar-toggle.expanded .quarto-sidebar-toggle-contents{padding-top:1em;padding-bottom:10px}.quarto-sidebar-toggle:not(.expanded) .quarto-sidebar-toggle-contents{padding-top:0px !important;padding-bottom:0px}nav[role=doc-toc]{z-index:1020}#quarto-sidebar>*,nav[role=doc-toc]>*{transition:opacity .1s ease,border .1s ease}#quarto-sidebar.slow>*,nav[role=doc-toc].slow>*{transition:opacity .4s ease,border .4s ease}.quarto-color-scheme-toggle:not(.alternate).top-right .bi::before{background-image:url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="rgba(142, 148, 151, 1)" class="bi bi-toggle-off" viewBox="0 0 16 16"><path d="M11 4a4 4 0 0 1 0 8H8a4.992 4.992 0 0 0 2-4 4.992 4.992 0 0 0-2-4h3zm-6 8a4 4 0 1 1 0-8 4 4 0 0 1 0 8zM0 8a5 5 0 0 0 5 5h6a5 5 0 0 0 0-10H5a5 5 0 0 0-5 5z"/></svg>')}.quarto-color-scheme-toggle.alternate.top-right .bi::before{background-image:url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="rgba(104, 109, 113, 1)" class="bi bi-toggle-on" viewBox="0 0 16 16"><path d="M5 3a5 5 0 0 0 0 10h6a5 5 0 0 0 0-10H5zm6 9a4 4 0 1 1 0-8 4 4 0 0 1 0 8z"/></svg>')}#quarto-appendix.default{border-top:1px solid #dee2e6}#quarto-appendix.default{background-color:#fff;padding-top:1.5em;margin-top:2em;z-index:998}#quarto-appendix.default .quarto-appendix-heading{margin-top:0;line-height:1.4em;font-weight:600;opacity:.9;border-bottom:none;margin-bottom:0}#quarto-appendix.default .footnotes ol,#quarto-appendix.default .footnotes ol li>p:last-of-type,#quarto-appendix.default .quarto-appendix-contents>p:last-of-type{margin-bottom:0}#quarto-appendix.default .quarto-appendix-secondary-label{margin-bottom:.4em}#quarto-appendix.default .quarto-appendix-bibtex{font-size:.7em;padding:1em;border:solid 1px #dee2e6;margin-bottom:1em}#quarto-appendix.default .quarto-appendix-bibtex code.sourceCode{white-space:pre-wrap}#quarto-appendix.default .quarto-appendix-citeas{font-size:.9em;padding:1em;border:solid 1px #dee2e6;margin-bottom:1em}#quarto-appendix.default .quarto-appendix-heading{font-size:1em !important}#quarto-appendix.default *[role=doc-endnotes]>ol,#quarto-appendix.default .quarto-appendix-contents>*:not(h2):not(.h2){font-size:.9em}#quarto-appendix.default section{padding-bottom:1.5em}#quarto-appendix.default section *[role=doc-endnotes],#quarto-appendix.default section>*:not(a){opacity:.9;word-wrap:break-word}.btn.btn-quarto,div.cell-output-display .btn-quarto{color:#cbcccc;background-color:#373a3c;border-color:#373a3c}.btn.btn-quarto:hover,div.cell-output-display .btn-quarto:hover{color:#cbcccc;background-color:#555859;border-color:#4b4e50}.btn-check:focus+.btn.btn-quarto,.btn.btn-quarto:focus,.btn-check:focus+div.cell-output-display .btn-quarto,div.cell-output-display .btn-quarto:focus{color:#cbcccc;background-color:#555859;border-color:#4b4e50;box-shadow:0 0 0 .25rem rgba(77,80,82,.5)}.btn-check:checked+.btn.btn-quarto,.btn-check:active+.btn.btn-quarto,.btn.btn-quarto:active,.btn.btn-quarto.active,.show>.btn.btn-quarto.dropdown-toggle,.btn-check:checked+div.cell-output-display .btn-quarto,.btn-check:active+div.cell-output-display .btn-quarto,div.cell-output-display .btn-quarto:active,div.cell-output-display .btn-quarto.active,.show>div.cell-output-display .btn-quarto.dropdown-toggle{color:#fff;background-color:#5f6163;border-color:#4b4e50}.btn-check:checked+.btn.btn-quarto:focus,.btn-check:active+.btn.btn-quarto:focus,.btn.btn-quarto:active:focus,.btn.btn-quarto.active:focus,.show>.btn.btn-quarto.dropdown-toggle:focus,.btn-check:checked+div.cell-output-display .btn-quarto:focus,.btn-check:active+div.cell-output-display .btn-quarto:focus,div.cell-output-display .btn-quarto:active:focus,div.cell-output-display .btn-quarto.active:focus,.show>div.cell-output-display .btn-quarto.dropdown-toggle:focus{box-shadow:0 0 0 .25rem rgba(77,80,82,.5)}.btn.btn-quarto:disabled,.btn.btn-quarto.disabled,div.cell-output-display .btn-quarto:disabled,div.cell-output-display .btn-quarto.disabled{color:#fff;background-color:#373a3c;border-color:#373a3c}nav.quarto-secondary-nav.color-navbar{background-color:#2780e3;color:#fdfeff}nav.quarto-secondary-nav.color-navbar h1,nav.quarto-secondary-nav.color-navbar .h1,nav.quarto-secondary-nav.color-navbar .quarto-btn-toggle{color:#fdfeff}@media(max-width: 991.98px){body.nav-sidebar .quarto-title-banner{margin-bottom:0;padding-bottom:0}body.nav-sidebar #title-block-header{margin-block-end:0}}p.subtitle{margin-top:.25em;margin-bottom:.5em}code a:any-link{color:inherit;text-decoration-color:#6c757d}/*! light */div.observablehq table thead tr th{background-color:var(--bs-body-bg)}input,button,select,optgroup,textarea{background-color:var(--bs-body-bg)}.code-annotated .code-copy-button{margin-right:1.25em;margin-top:0;padding-bottom:0;padding-top:3px}.code-annotation-gutter-bg{background-color:#fff}.code-annotation-gutter{background-color:rgba(233,236,239,.65)}.code-annotation-gutter,.code-annotation-gutter-bg{height:100%;width:calc(20px + .5em);position:absolute;top:0;right:0}dl.code-annotation-container-grid dt{margin-right:1em;margin-top:.25rem}dl.code-annotation-container-grid dt{font-family:var(--bs-font-monospace);color:#4f5457;border:solid #4f5457 1px;border-radius:50%;height:22px;width:22px;line-height:22px;font-size:11px;text-align:center;vertical-align:middle;text-decoration:none}dl.code-annotation-container-grid dt[data-target-cell]{cursor:pointer}dl.code-annotation-container-grid dt[data-target-cell].code-annotation-active{color:#fff;border:solid #aaa 1px;background-color:#aaa}pre.code-annotation-code{padding-top:0;padding-bottom:0}pre.code-annotation-code code{z-index:3}#code-annotation-line-highlight-gutter{width:100%;border-top:solid rgba(170,170,170,.2666666667) 1px;border-bottom:solid rgba(170,170,170,.2666666667) 1px;z-index:2;background-color:rgba(170,170,170,.1333333333)}#code-annotation-line-highlight{margin-left:-4em;width:calc(100% + 4em);border-top:solid rgba(170,170,170,.2666666667) 1px;border-bottom:solid rgba(170,170,170,.2666666667) 1px;z-index:2;background-color:rgba(170,170,170,.1333333333)}code.sourceCode .code-annotation-anchor.code-annotation-active{background-color:var(--quarto-hl-normal-color, #aaaaaa);border:solid var(--quarto-hl-normal-color, #aaaaaa) 1px;color:#e9ecef;font-weight:bolder}code.sourceCode .code-annotation-anchor{font-family:var(--bs-font-monospace);color:var(--quarto-hl-co-color);border:solid var(--quarto-hl-co-color) 1px;border-radius:50%;height:18px;width:18px;font-size:9px;margin-top:2px}code.sourceCode button.code-annotation-anchor{padding:2px}code.sourceCode a.code-annotation-anchor{line-height:18px;text-align:center;vertical-align:middle;cursor:default;text-decoration:none}@media print{.page-columns .column-screen-inset{grid-column:page-start-inset/page-end-inset;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen-inset table{background:#fff}.page-columns .column-screen-inset-left{grid-column:page-start-inset/body-content-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen-inset-left table{background:#fff}.page-columns .column-screen-inset-right{grid-column:body-content-start/page-end-inset;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen-inset-right table{background:#fff}.page-columns .column-screen{grid-column:page-start/page-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen table{background:#fff}.page-columns .column-screen-left{grid-column:page-start/body-content-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen-left table{background:#fff}.page-columns .column-screen-right{grid-column:body-content-start/page-end;z-index:998;transform:translate3d(0, 0, 0)}.page-columns .column-screen-right table{background:#fff}.page-columns .column-screen-inset-shaded{grid-column:page-start-inset/page-end-inset;padding:1em;background:#f8f9fa;z-index:998;transform:translate3d(0, 0, 0);margin-bottom:1em}}.quarto-video{margin-bottom:1em}.table>thead{border-top-width:0}.table>:not(caption)>*:not(:last-child)>*{border-bottom-color:#ebeced;border-bottom-style:solid;border-bottom-width:1px}.table>:not(:first-child){border-top:1px solid #b6babc;border-bottom:1px solid inherit}.table tbody{border-bottom-color:#b6babc}a.external:after{display:inline-block;height:.75rem;width:.75rem;margin-bottom:.15em;margin-left:.25em;content:"";vertical-align:-0.125em;background-image:url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="rgb(39, 128, 227)" class="bi bi-box-arrow-up-right" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M8.636 3.5a.5.5 0 0 0-.5-.5H1.5A1.5 1.5 0 0 0 0 4.5v10A1.5 1.5 0 0 0 1.5 16h10a1.5 1.5 0 0 0 1.5-1.5V7.864a.5.5 0 0 0-1 0V14.5a.5.5 0 0 1-.5.5h-10a.5.5 0 0 1-.5-.5v-10a.5.5 0 0 1 .5-.5h6.636a.5.5 0 0 0 .5-.5z"/><path fill-rule="evenodd" d="M16 .5a.5.5 0 0 0-.5-.5h-5a.5.5 0 0 0 0 1h3.793L6.146 9.146a.5.5 0 1 0 .708.708L15 1.707V5.5a.5.5 0 0 0 1 0v-5z"/></svg>');background-repeat:no-repeat;background-size:.75rem .75rem}div.sourceCode code a.external:after{content:none}a.external:after:hover{cursor:pointer}.quarto-ext-icon{display:inline-block;font-size:.75em;padding-left:.3em}.code-with-filename .code-with-filename-file{margin-bottom:0;padding-bottom:2px;padding-top:2px;padding-left:.7em;border:var(--quarto-border-width) solid var(--quarto-border-color);border-radius:var(--quarto-border-radius);border-bottom:0;border-bottom-left-radius:0%;border-bottom-right-radius:0%}.code-with-filename div.sourceCode,.reveal .code-with-filename div.sourceCode{margin-top:0;border-top-left-radius:0%;border-top-right-radius:0%}.code-with-filename .code-with-filename-file pre{margin-bottom:0}.code-with-filename .code-with-filename-file,.code-with-filename .code-with-filename-file pre{background-color:rgba(219,219,219,.8)}.quarto-dark .code-with-filename .code-with-filename-file,.quarto-dark .code-with-filename .code-with-filename-file pre{background-color:#555}.code-with-filename .code-with-filename-file strong{font-weight:400}.quarto-title-banner{margin-bottom:1em;color:#fdfeff;background:#2780e3}.quarto-title-banner .code-tools-button{color:#97cbff}.quarto-title-banner .code-tools-button:hover{color:#fdfeff}.quarto-title-banner .code-tools-button>.bi::before{background-image:url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="rgb(151, 203, 255)" viewBox="0 0 16 16"><path d="M10.478 1.647a.5.5 0 1 0-.956-.294l-4 13a.5.5 0 0 0 .956.294l4-13zM4.854 4.146a.5.5 0 0 1 0 .708L1.707 8l3.147 3.146a.5.5 0 0 1-.708.708l-3.5-3.5a.5.5 0 0 1 0-.708l3.5-3.5a.5.5 0 0 1 .708 0zm6.292 0a.5.5 0 0 0 0 .708L14.293 8l-3.147 3.146a.5.5 0 0 0 .708.708l3.5-3.5a.5.5 0 0 0 0-.708l-3.5-3.5a.5.5 0 0 0-.708 0z"/></svg>')}.quarto-title-banner .code-tools-button:hover>.bi::before{background-image:url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="rgb(253, 254, 255)" viewBox="0 0 16 16"><path d="M10.478 1.647a.5.5 0 1 0-.956-.294l-4 13a.5.5 0 0 0 .956.294l4-13zM4.854 4.146a.5.5 0 0 1 0 .708L1.707 8l3.147 3.146a.5.5 0 0 1-.708.708l-3.5-3.5a.5.5 0 0 1 0-.708l3.5-3.5a.5.5 0 0 1 .708 0zm6.292 0a.5.5 0 0 0 0 .708L14.293 8l-3.147 3.146a.5.5 0 0 0 .708.708l3.5-3.5a.5.5 0 0 0 0-.708l-3.5-3.5a.5.5 0 0 0-.708 0z"/></svg>')}.quarto-title-banner .quarto-title .title{font-weight:600}.quarto-title-banner .quarto-categories{margin-top:.75em}@media(min-width: 992px){.quarto-title-banner{padding-top:2.5em;padding-bottom:2.5em}}@media(max-width: 991.98px){.quarto-title-banner{padding-top:1em;padding-bottom:1em}}main.quarto-banner-title-block>section:first-child>h2,main.quarto-banner-title-block>section:first-child>.h2,main.quarto-banner-title-block>section:first-child>h3,main.quarto-banner-title-block>section:first-child>.h3,main.quarto-banner-title-block>section:first-child>h4,main.quarto-banner-title-block>section:first-child>.h4{margin-top:0}.quarto-title .quarto-categories{display:flex;flex-wrap:wrap;row-gap:.5em;column-gap:.4em;padding-bottom:.5em;margin-top:.75em}.quarto-title .quarto-categories .quarto-category{padding:.25em .75em;font-size:.65em;text-transform:uppercase;border:solid 1px;border-radius:.25rem;opacity:.6}.quarto-title .quarto-categories .quarto-category a{color:inherit}#title-block-header.quarto-title-block.default .quarto-title-meta{display:grid;grid-template-columns:repeat(2, 1fr)}#title-block-header.quarto-title-block.default .quarto-title .title{margin-bottom:0}#title-block-header.quarto-title-block.default .quarto-title-author-orcid img{margin-top:-5px}#title-block-header.quarto-title-block.default .quarto-description p:last-of-type{margin-bottom:0}#title-block-header.quarto-title-block.default .quarto-title-meta-contents p,#title-block-header.quarto-title-block.default .quarto-title-authors p,#title-block-header.quarto-title-block.default .quarto-title-affiliations p{margin-bottom:.1em}#title-block-header.quarto-title-block.default .quarto-title-meta-heading{text-transform:uppercase;margin-top:1em;font-size:.8em;opacity:.8;font-weight:400}#title-block-header.quarto-title-block.default .quarto-title-meta-contents{font-size:.9em}#title-block-header.quarto-title-block.default .quarto-title-meta-contents a{color:#373a3c}#title-block-header.quarto-title-block.default .quarto-title-meta-contents p.affiliation:last-of-type{margin-bottom:.7em}#title-block-header.quarto-title-block.default p.affiliation{margin-bottom:.1em}#title-block-header.quarto-title-block.default .description,#title-block-header.quarto-title-block.default .abstract{margin-top:0}#title-block-header.quarto-title-block.default .description>p,#title-block-header.quarto-title-block.default .abstract>p{font-size:.9em}#title-block-header.quarto-title-block.default .description>p:last-of-type,#title-block-header.quarto-title-block.default .abstract>p:last-of-type{margin-bottom:0}#title-block-header.quarto-title-block.default .description .abstract-title,#title-block-header.quarto-title-block.default .abstract .abstract-title{margin-top:1em;text-transform:uppercase;font-size:.8em;opacity:.8;font-weight:400}#title-block-header.quarto-title-block.default .quarto-title-meta-author{display:grid;grid-template-columns:1fr 1fr}.quarto-title-tools-only{display:flex;justify-content:right}body{-webkit-font-smoothing:antialiased}.badge.bg-light{color:#373a3c}.progress .progress-bar{font-size:8px;line-height:8px}/*# sourceMappingURL=9161419e6f82ea4435380a70856fa72b.css.map */ diff --git a/site_libs/bootstrap/bootstrap.min.js b/site_libs/bootstrap/bootstrap.min.js new file mode 100644 index 00000000..cc0a2556 --- /dev/null +++ b/site_libs/bootstrap/bootstrap.min.js @@ -0,0 +1,7 @@ +/*! + * Bootstrap v5.1.3 (https://getbootstrap.com/) + * Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) + * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE) + */ +!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(t="undefined"!=typeof globalThis?globalThis:t||self).bootstrap=e()}(this,(function(){"use strict";const t="transitionend",e=t=>{let e=t.getAttribute("data-bs-target");if(!e||"#"===e){let i=t.getAttribute("href");if(!i||!i.includes("#")&&!i.startsWith("."))return null;i.includes("#")&&!i.startsWith("#")&&(i=`#${i.split("#")[1]}`),e=i&&"#"!==i?i.trim():null}return e},i=t=>{const i=e(t);return i&&document.querySelector(i)?i:null},n=t=>{const i=e(t);return i?document.querySelector(i):null},s=e=>{e.dispatchEvent(new Event(t))},o=t=>!(!t||"object"!=typeof t)&&(void 0!==t.jquery&&(t=t[0]),void 0!==t.nodeType),r=t=>o(t)?t.jquery?t[0]:t:"string"==typeof t&&t.length>0?document.querySelector(t):null,a=(t,e,i)=>{Object.keys(i).forEach((n=>{const s=i[n],r=e[n],a=r&&o(r)?"element":null==(l=r)?`${l}`:{}.toString.call(l).match(/\s([a-z]+)/i)[1].toLowerCase();var l;if(!new RegExp(s).test(a))throw new TypeError(`${t.toUpperCase()}: Option "${n}" provided type "${a}" but expected type "${s}".`)}))},l=t=>!(!o(t)||0===t.getClientRects().length)&&"visible"===getComputedStyle(t).getPropertyValue("visibility"),c=t=>!t||t.nodeType!==Node.ELEMENT_NODE||!!t.classList.contains("disabled")||(void 0!==t.disabled?t.disabled:t.hasAttribute("disabled")&&"false"!==t.getAttribute("disabled")),h=t=>{if(!document.documentElement.attachShadow)return null;if("function"==typeof t.getRootNode){const e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:t.parentNode?h(t.parentNode):null},d=()=>{},u=t=>{t.offsetHeight},f=()=>{const{jQuery:t}=window;return t&&!document.body.hasAttribute("data-bs-no-jquery")?t:null},p=[],m=()=>"rtl"===document.documentElement.dir,g=t=>{var e;e=()=>{const e=f();if(e){const i=t.NAME,n=e.fn[i];e.fn[i]=t.jQueryInterface,e.fn[i].Constructor=t,e.fn[i].noConflict=()=>(e.fn[i]=n,t.jQueryInterface)}},"loading"===document.readyState?(p.length||document.addEventListener("DOMContentLoaded",(()=>{p.forEach((t=>t()))})),p.push(e)):e()},_=t=>{"function"==typeof t&&t()},b=(e,i,n=!0)=>{if(!n)return void _(e);const o=(t=>{if(!t)return 0;let{transitionDuration:e,transitionDelay:i}=window.getComputedStyle(t);const n=Number.parseFloat(e),s=Number.parseFloat(i);return n||s?(e=e.split(",")[0],i=i.split(",")[0],1e3*(Number.parseFloat(e)+Number.parseFloat(i))):0})(i)+5;let r=!1;const a=({target:n})=>{n===i&&(r=!0,i.removeEventListener(t,a),_(e))};i.addEventListener(t,a),setTimeout((()=>{r||s(i)}),o)},v=(t,e,i,n)=>{let s=t.indexOf(e);if(-1===s)return t[!i&&n?t.length-1:0];const o=t.length;return s+=i?1:-1,n&&(s=(s+o)%o),t[Math.max(0,Math.min(s,o-1))]},y=/[^.]*(?=\..*)\.|.*/,w=/\..*/,E=/::\d+$/,A={};let T=1;const O={mouseenter:"mouseover",mouseleave:"mouseout"},C=/^(mouseenter|mouseleave)/i,k=new Set(["click","dblclick","mouseup","mousedown","contextmenu","mousewheel","DOMMouseScroll","mouseover","mouseout","mousemove","selectstart","selectend","keydown","keypress","keyup","orientationchange","touchstart","touchmove","touchend","touchcancel","pointerdown","pointermove","pointerup","pointerleave","pointercancel","gesturestart","gesturechange","gestureend","focus","blur","change","reset","select","submit","focusin","focusout","load","unload","beforeunload","resize","move","DOMContentLoaded","readystatechange","error","abort","scroll"]);function L(t,e){return e&&`${e}::${T++}`||t.uidEvent||T++}function x(t){const e=L(t);return t.uidEvent=e,A[e]=A[e]||{},A[e]}function D(t,e,i=null){const n=Object.keys(t);for(let s=0,o=n.length;s<o;s++){const o=t[n[s]];if(o.originalHandler===e&&o.delegationSelector===i)return o}return null}function S(t,e,i){const n="string"==typeof e,s=n?i:e;let o=P(t);return k.has(o)||(o=t),[n,s,o]}function N(t,e,i,n,s){if("string"!=typeof e||!t)return;if(i||(i=n,n=null),C.test(e)){const t=t=>function(e){if(!e.relatedTarget||e.relatedTarget!==e.delegateTarget&&!e.delegateTarget.contains(e.relatedTarget))return t.call(this,e)};n?n=t(n):i=t(i)}const[o,r,a]=S(e,i,n),l=x(t),c=l[a]||(l[a]={}),h=D(c,r,o?i:null);if(h)return void(h.oneOff=h.oneOff&&s);const d=L(r,e.replace(y,"")),u=o?function(t,e,i){return function n(s){const o=t.querySelectorAll(e);for(let{target:r}=s;r&&r!==this;r=r.parentNode)for(let a=o.length;a--;)if(o[a]===r)return s.delegateTarget=r,n.oneOff&&j.off(t,s.type,e,i),i.apply(r,[s]);return null}}(t,i,n):function(t,e){return function i(n){return n.delegateTarget=t,i.oneOff&&j.off(t,n.type,e),e.apply(t,[n])}}(t,i);u.delegationSelector=o?i:null,u.originalHandler=r,u.oneOff=s,u.uidEvent=d,c[d]=u,t.addEventListener(a,u,o)}function I(t,e,i,n,s){const o=D(e[i],n,s);o&&(t.removeEventListener(i,o,Boolean(s)),delete e[i][o.uidEvent])}function P(t){return t=t.replace(w,""),O[t]||t}const j={on(t,e,i,n){N(t,e,i,n,!1)},one(t,e,i,n){N(t,e,i,n,!0)},off(t,e,i,n){if("string"!=typeof e||!t)return;const[s,o,r]=S(e,i,n),a=r!==e,l=x(t),c=e.startsWith(".");if(void 0!==o){if(!l||!l[r])return;return void I(t,l,r,o,s?i:null)}c&&Object.keys(l).forEach((i=>{!function(t,e,i,n){const s=e[i]||{};Object.keys(s).forEach((o=>{if(o.includes(n)){const n=s[o];I(t,e,i,n.originalHandler,n.delegationSelector)}}))}(t,l,i,e.slice(1))}));const h=l[r]||{};Object.keys(h).forEach((i=>{const n=i.replace(E,"");if(!a||e.includes(n)){const e=h[i];I(t,l,r,e.originalHandler,e.delegationSelector)}}))},trigger(t,e,i){if("string"!=typeof e||!t)return null;const n=f(),s=P(e),o=e!==s,r=k.has(s);let a,l=!0,c=!0,h=!1,d=null;return o&&n&&(a=n.Event(e,i),n(t).trigger(a),l=!a.isPropagationStopped(),c=!a.isImmediatePropagationStopped(),h=a.isDefaultPrevented()),r?(d=document.createEvent("HTMLEvents"),d.initEvent(s,l,!0)):d=new CustomEvent(e,{bubbles:l,cancelable:!0}),void 0!==i&&Object.keys(i).forEach((t=>{Object.defineProperty(d,t,{get:()=>i[t]})})),h&&d.preventDefault(),c&&t.dispatchEvent(d),d.defaultPrevented&&void 0!==a&&a.preventDefault(),d}},M=new Map,H={set(t,e,i){M.has(t)||M.set(t,new Map);const n=M.get(t);n.has(e)||0===n.size?n.set(e,i):console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(n.keys())[0]}.`)},get:(t,e)=>M.has(t)&&M.get(t).get(e)||null,remove(t,e){if(!M.has(t))return;const i=M.get(t);i.delete(e),0===i.size&&M.delete(t)}};class B{constructor(t){(t=r(t))&&(this._element=t,H.set(this._element,this.constructor.DATA_KEY,this))}dispose(){H.remove(this._element,this.constructor.DATA_KEY),j.off(this._element,this.constructor.EVENT_KEY),Object.getOwnPropertyNames(this).forEach((t=>{this[t]=null}))}_queueCallback(t,e,i=!0){b(t,e,i)}static getInstance(t){return H.get(r(t),this.DATA_KEY)}static getOrCreateInstance(t,e={}){return this.getInstance(t)||new this(t,"object"==typeof e?e:null)}static get VERSION(){return"5.1.3"}static get NAME(){throw new Error('You have to implement the static method "NAME", for each component!')}static get DATA_KEY(){return`bs.${this.NAME}`}static get EVENT_KEY(){return`.${this.DATA_KEY}`}}const R=(t,e="hide")=>{const i=`click.dismiss${t.EVENT_KEY}`,s=t.NAME;j.on(document,i,`[data-bs-dismiss="${s}"]`,(function(i){if(["A","AREA"].includes(this.tagName)&&i.preventDefault(),c(this))return;const o=n(this)||this.closest(`.${s}`);t.getOrCreateInstance(o)[e]()}))};class W extends B{static get NAME(){return"alert"}close(){if(j.trigger(this._element,"close.bs.alert").defaultPrevented)return;this._element.classList.remove("show");const t=this._element.classList.contains("fade");this._queueCallback((()=>this._destroyElement()),this._element,t)}_destroyElement(){this._element.remove(),j.trigger(this._element,"closed.bs.alert"),this.dispose()}static jQueryInterface(t){return this.each((function(){const e=W.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}R(W,"close"),g(W);const $='[data-bs-toggle="button"]';class z extends B{static get NAME(){return"button"}toggle(){this._element.setAttribute("aria-pressed",this._element.classList.toggle("active"))}static jQueryInterface(t){return this.each((function(){const e=z.getOrCreateInstance(this);"toggle"===t&&e[t]()}))}}function q(t){return"true"===t||"false"!==t&&(t===Number(t).toString()?Number(t):""===t||"null"===t?null:t)}function F(t){return t.replace(/[A-Z]/g,(t=>`-${t.toLowerCase()}`))}j.on(document,"click.bs.button.data-api",$,(t=>{t.preventDefault();const e=t.target.closest($);z.getOrCreateInstance(e).toggle()})),g(z);const U={setDataAttribute(t,e,i){t.setAttribute(`data-bs-${F(e)}`,i)},removeDataAttribute(t,e){t.removeAttribute(`data-bs-${F(e)}`)},getDataAttributes(t){if(!t)return{};const e={};return Object.keys(t.dataset).filter((t=>t.startsWith("bs"))).forEach((i=>{let n=i.replace(/^bs/,"");n=n.charAt(0).toLowerCase()+n.slice(1,n.length),e[n]=q(t.dataset[i])})),e},getDataAttribute:(t,e)=>q(t.getAttribute(`data-bs-${F(e)}`)),offset(t){const e=t.getBoundingClientRect();return{top:e.top+window.pageYOffset,left:e.left+window.pageXOffset}},position:t=>({top:t.offsetTop,left:t.offsetLeft})},V={find:(t,e=document.documentElement)=>[].concat(...Element.prototype.querySelectorAll.call(e,t)),findOne:(t,e=document.documentElement)=>Element.prototype.querySelector.call(e,t),children:(t,e)=>[].concat(...t.children).filter((t=>t.matches(e))),parents(t,e){const i=[];let n=t.parentNode;for(;n&&n.nodeType===Node.ELEMENT_NODE&&3!==n.nodeType;)n.matches(e)&&i.push(n),n=n.parentNode;return i},prev(t,e){let i=t.previousElementSibling;for(;i;){if(i.matches(e))return[i];i=i.previousElementSibling}return[]},next(t,e){let i=t.nextElementSibling;for(;i;){if(i.matches(e))return[i];i=i.nextElementSibling}return[]},focusableChildren(t){const e=["a","button","input","textarea","select","details","[tabindex]",'[contenteditable="true"]'].map((t=>`${t}:not([tabindex^="-"])`)).join(", ");return this.find(e,t).filter((t=>!c(t)&&l(t)))}},K="carousel",X={interval:5e3,keyboard:!0,slide:!1,pause:"hover",wrap:!0,touch:!0},Y={interval:"(number|boolean)",keyboard:"boolean",slide:"(boolean|string)",pause:"(string|boolean)",wrap:"boolean",touch:"boolean"},Q="next",G="prev",Z="left",J="right",tt={ArrowLeft:J,ArrowRight:Z},et="slid.bs.carousel",it="active",nt=".active.carousel-item";class st extends B{constructor(t,e){super(t),this._items=null,this._interval=null,this._activeElement=null,this._isPaused=!1,this._isSliding=!1,this.touchTimeout=null,this.touchStartX=0,this.touchDeltaX=0,this._config=this._getConfig(e),this._indicatorsElement=V.findOne(".carousel-indicators",this._element),this._touchSupported="ontouchstart"in document.documentElement||navigator.maxTouchPoints>0,this._pointerEvent=Boolean(window.PointerEvent),this._addEventListeners()}static get Default(){return X}static get NAME(){return K}next(){this._slide(Q)}nextWhenVisible(){!document.hidden&&l(this._element)&&this.next()}prev(){this._slide(G)}pause(t){t||(this._isPaused=!0),V.findOne(".carousel-item-next, .carousel-item-prev",this._element)&&(s(this._element),this.cycle(!0)),clearInterval(this._interval),this._interval=null}cycle(t){t||(this._isPaused=!1),this._interval&&(clearInterval(this._interval),this._interval=null),this._config&&this._config.interval&&!this._isPaused&&(this._updateInterval(),this._interval=setInterval((document.visibilityState?this.nextWhenVisible:this.next).bind(this),this._config.interval))}to(t){this._activeElement=V.findOne(nt,this._element);const e=this._getItemIndex(this._activeElement);if(t>this._items.length-1||t<0)return;if(this._isSliding)return void j.one(this._element,et,(()=>this.to(t)));if(e===t)return this.pause(),void this.cycle();const i=t>e?Q:G;this._slide(i,this._items[t])}_getConfig(t){return t={...X,...U.getDataAttributes(this._element),..."object"==typeof t?t:{}},a(K,t,Y),t}_handleSwipe(){const t=Math.abs(this.touchDeltaX);if(t<=40)return;const e=t/this.touchDeltaX;this.touchDeltaX=0,e&&this._slide(e>0?J:Z)}_addEventListeners(){this._config.keyboard&&j.on(this._element,"keydown.bs.carousel",(t=>this._keydown(t))),"hover"===this._config.pause&&(j.on(this._element,"mouseenter.bs.carousel",(t=>this.pause(t))),j.on(this._element,"mouseleave.bs.carousel",(t=>this.cycle(t)))),this._config.touch&&this._touchSupported&&this._addTouchEventListeners()}_addTouchEventListeners(){const t=t=>this._pointerEvent&&("pen"===t.pointerType||"touch"===t.pointerType),e=e=>{t(e)?this.touchStartX=e.clientX:this._pointerEvent||(this.touchStartX=e.touches[0].clientX)},i=t=>{this.touchDeltaX=t.touches&&t.touches.length>1?0:t.touches[0].clientX-this.touchStartX},n=e=>{t(e)&&(this.touchDeltaX=e.clientX-this.touchStartX),this._handleSwipe(),"hover"===this._config.pause&&(this.pause(),this.touchTimeout&&clearTimeout(this.touchTimeout),this.touchTimeout=setTimeout((t=>this.cycle(t)),500+this._config.interval))};V.find(".carousel-item img",this._element).forEach((t=>{j.on(t,"dragstart.bs.carousel",(t=>t.preventDefault()))})),this._pointerEvent?(j.on(this._element,"pointerdown.bs.carousel",(t=>e(t))),j.on(this._element,"pointerup.bs.carousel",(t=>n(t))),this._element.classList.add("pointer-event")):(j.on(this._element,"touchstart.bs.carousel",(t=>e(t))),j.on(this._element,"touchmove.bs.carousel",(t=>i(t))),j.on(this._element,"touchend.bs.carousel",(t=>n(t))))}_keydown(t){if(/input|textarea/i.test(t.target.tagName))return;const e=tt[t.key];e&&(t.preventDefault(),this._slide(e))}_getItemIndex(t){return this._items=t&&t.parentNode?V.find(".carousel-item",t.parentNode):[],this._items.indexOf(t)}_getItemByOrder(t,e){const i=t===Q;return v(this._items,e,i,this._config.wrap)}_triggerSlideEvent(t,e){const i=this._getItemIndex(t),n=this._getItemIndex(V.findOne(nt,this._element));return j.trigger(this._element,"slide.bs.carousel",{relatedTarget:t,direction:e,from:n,to:i})}_setActiveIndicatorElement(t){if(this._indicatorsElement){const e=V.findOne(".active",this._indicatorsElement);e.classList.remove(it),e.removeAttribute("aria-current");const i=V.find("[data-bs-target]",this._indicatorsElement);for(let e=0;e<i.length;e++)if(Number.parseInt(i[e].getAttribute("data-bs-slide-to"),10)===this._getItemIndex(t)){i[e].classList.add(it),i[e].setAttribute("aria-current","true");break}}}_updateInterval(){const t=this._activeElement||V.findOne(nt,this._element);if(!t)return;const e=Number.parseInt(t.getAttribute("data-bs-interval"),10);e?(this._config.defaultInterval=this._config.defaultInterval||this._config.interval,this._config.interval=e):this._config.interval=this._config.defaultInterval||this._config.interval}_slide(t,e){const i=this._directionToOrder(t),n=V.findOne(nt,this._element),s=this._getItemIndex(n),o=e||this._getItemByOrder(i,n),r=this._getItemIndex(o),a=Boolean(this._interval),l=i===Q,c=l?"carousel-item-start":"carousel-item-end",h=l?"carousel-item-next":"carousel-item-prev",d=this._orderToDirection(i);if(o&&o.classList.contains(it))return void(this._isSliding=!1);if(this._isSliding)return;if(this._triggerSlideEvent(o,d).defaultPrevented)return;if(!n||!o)return;this._isSliding=!0,a&&this.pause(),this._setActiveIndicatorElement(o),this._activeElement=o;const f=()=>{j.trigger(this._element,et,{relatedTarget:o,direction:d,from:s,to:r})};if(this._element.classList.contains("slide")){o.classList.add(h),u(o),n.classList.add(c),o.classList.add(c);const t=()=>{o.classList.remove(c,h),o.classList.add(it),n.classList.remove(it,h,c),this._isSliding=!1,setTimeout(f,0)};this._queueCallback(t,n,!0)}else n.classList.remove(it),o.classList.add(it),this._isSliding=!1,f();a&&this.cycle()}_directionToOrder(t){return[J,Z].includes(t)?m()?t===Z?G:Q:t===Z?Q:G:t}_orderToDirection(t){return[Q,G].includes(t)?m()?t===G?Z:J:t===G?J:Z:t}static carouselInterface(t,e){const i=st.getOrCreateInstance(t,e);let{_config:n}=i;"object"==typeof e&&(n={...n,...e});const s="string"==typeof e?e:n.slide;if("number"==typeof e)i.to(e);else if("string"==typeof s){if(void 0===i[s])throw new TypeError(`No method named "${s}"`);i[s]()}else n.interval&&n.ride&&(i.pause(),i.cycle())}static jQueryInterface(t){return this.each((function(){st.carouselInterface(this,t)}))}static dataApiClickHandler(t){const e=n(this);if(!e||!e.classList.contains("carousel"))return;const i={...U.getDataAttributes(e),...U.getDataAttributes(this)},s=this.getAttribute("data-bs-slide-to");s&&(i.interval=!1),st.carouselInterface(e,i),s&&st.getInstance(e).to(s),t.preventDefault()}}j.on(document,"click.bs.carousel.data-api","[data-bs-slide], [data-bs-slide-to]",st.dataApiClickHandler),j.on(window,"load.bs.carousel.data-api",(()=>{const t=V.find('[data-bs-ride="carousel"]');for(let e=0,i=t.length;e<i;e++)st.carouselInterface(t[e],st.getInstance(t[e]))})),g(st);const ot="collapse",rt={toggle:!0,parent:null},at={toggle:"boolean",parent:"(null|element)"},lt="show",ct="collapse",ht="collapsing",dt="collapsed",ut=":scope .collapse .collapse",ft='[data-bs-toggle="collapse"]';class pt extends B{constructor(t,e){super(t),this._isTransitioning=!1,this._config=this._getConfig(e),this._triggerArray=[];const n=V.find(ft);for(let t=0,e=n.length;t<e;t++){const e=n[t],s=i(e),o=V.find(s).filter((t=>t===this._element));null!==s&&o.length&&(this._selector=s,this._triggerArray.push(e))}this._initializeChildren(),this._config.parent||this._addAriaAndCollapsedClass(this._triggerArray,this._isShown()),this._config.toggle&&this.toggle()}static get Default(){return rt}static get NAME(){return ot}toggle(){this._isShown()?this.hide():this.show()}show(){if(this._isTransitioning||this._isShown())return;let t,e=[];if(this._config.parent){const t=V.find(ut,this._config.parent);e=V.find(".collapse.show, .collapse.collapsing",this._config.parent).filter((e=>!t.includes(e)))}const i=V.findOne(this._selector);if(e.length){const n=e.find((t=>i!==t));if(t=n?pt.getInstance(n):null,t&&t._isTransitioning)return}if(j.trigger(this._element,"show.bs.collapse").defaultPrevented)return;e.forEach((e=>{i!==e&&pt.getOrCreateInstance(e,{toggle:!1}).hide(),t||H.set(e,"bs.collapse",null)}));const n=this._getDimension();this._element.classList.remove(ct),this._element.classList.add(ht),this._element.style[n]=0,this._addAriaAndCollapsedClass(this._triggerArray,!0),this._isTransitioning=!0;const s=`scroll${n[0].toUpperCase()+n.slice(1)}`;this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(ht),this._element.classList.add(ct,lt),this._element.style[n]="",j.trigger(this._element,"shown.bs.collapse")}),this._element,!0),this._element.style[n]=`${this._element[s]}px`}hide(){if(this._isTransitioning||!this._isShown())return;if(j.trigger(this._element,"hide.bs.collapse").defaultPrevented)return;const t=this._getDimension();this._element.style[t]=`${this._element.getBoundingClientRect()[t]}px`,u(this._element),this._element.classList.add(ht),this._element.classList.remove(ct,lt);const e=this._triggerArray.length;for(let t=0;t<e;t++){const e=this._triggerArray[t],i=n(e);i&&!this._isShown(i)&&this._addAriaAndCollapsedClass([e],!1)}this._isTransitioning=!0,this._element.style[t]="",this._queueCallback((()=>{this._isTransitioning=!1,this._element.classList.remove(ht),this._element.classList.add(ct),j.trigger(this._element,"hidden.bs.collapse")}),this._element,!0)}_isShown(t=this._element){return t.classList.contains(lt)}_getConfig(t){return(t={...rt,...U.getDataAttributes(this._element),...t}).toggle=Boolean(t.toggle),t.parent=r(t.parent),a(ot,t,at),t}_getDimension(){return this._element.classList.contains("collapse-horizontal")?"width":"height"}_initializeChildren(){if(!this._config.parent)return;const t=V.find(ut,this._config.parent);V.find(ft,this._config.parent).filter((e=>!t.includes(e))).forEach((t=>{const e=n(t);e&&this._addAriaAndCollapsedClass([t],this._isShown(e))}))}_addAriaAndCollapsedClass(t,e){t.length&&t.forEach((t=>{e?t.classList.remove(dt):t.classList.add(dt),t.setAttribute("aria-expanded",e)}))}static jQueryInterface(t){return this.each((function(){const e={};"string"==typeof t&&/show|hide/.test(t)&&(e.toggle=!1);const i=pt.getOrCreateInstance(this,e);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t]()}}))}}j.on(document,"click.bs.collapse.data-api",ft,(function(t){("A"===t.target.tagName||t.delegateTarget&&"A"===t.delegateTarget.tagName)&&t.preventDefault();const e=i(this);V.find(e).forEach((t=>{pt.getOrCreateInstance(t,{toggle:!1}).toggle()}))})),g(pt);var mt="top",gt="bottom",_t="right",bt="left",vt="auto",yt=[mt,gt,_t,bt],wt="start",Et="end",At="clippingParents",Tt="viewport",Ot="popper",Ct="reference",kt=yt.reduce((function(t,e){return t.concat([e+"-"+wt,e+"-"+Et])}),[]),Lt=[].concat(yt,[vt]).reduce((function(t,e){return t.concat([e,e+"-"+wt,e+"-"+Et])}),[]),xt="beforeRead",Dt="read",St="afterRead",Nt="beforeMain",It="main",Pt="afterMain",jt="beforeWrite",Mt="write",Ht="afterWrite",Bt=[xt,Dt,St,Nt,It,Pt,jt,Mt,Ht];function Rt(t){return t?(t.nodeName||"").toLowerCase():null}function Wt(t){if(null==t)return window;if("[object Window]"!==t.toString()){var e=t.ownerDocument;return e&&e.defaultView||window}return t}function $t(t){return t instanceof Wt(t).Element||t instanceof Element}function zt(t){return t instanceof Wt(t).HTMLElement||t instanceof HTMLElement}function qt(t){return"undefined"!=typeof ShadowRoot&&(t instanceof Wt(t).ShadowRoot||t instanceof ShadowRoot)}const Ft={name:"applyStyles",enabled:!0,phase:"write",fn:function(t){var e=t.state;Object.keys(e.elements).forEach((function(t){var i=e.styles[t]||{},n=e.attributes[t]||{},s=e.elements[t];zt(s)&&Rt(s)&&(Object.assign(s.style,i),Object.keys(n).forEach((function(t){var e=n[t];!1===e?s.removeAttribute(t):s.setAttribute(t,!0===e?"":e)})))}))},effect:function(t){var e=t.state,i={popper:{position:e.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};return Object.assign(e.elements.popper.style,i.popper),e.styles=i,e.elements.arrow&&Object.assign(e.elements.arrow.style,i.arrow),function(){Object.keys(e.elements).forEach((function(t){var n=e.elements[t],s=e.attributes[t]||{},o=Object.keys(e.styles.hasOwnProperty(t)?e.styles[t]:i[t]).reduce((function(t,e){return t[e]="",t}),{});zt(n)&&Rt(n)&&(Object.assign(n.style,o),Object.keys(s).forEach((function(t){n.removeAttribute(t)})))}))}},requires:["computeStyles"]};function Ut(t){return t.split("-")[0]}function Vt(t,e){var i=t.getBoundingClientRect();return{width:i.width/1,height:i.height/1,top:i.top/1,right:i.right/1,bottom:i.bottom/1,left:i.left/1,x:i.left/1,y:i.top/1}}function Kt(t){var e=Vt(t),i=t.offsetWidth,n=t.offsetHeight;return Math.abs(e.width-i)<=1&&(i=e.width),Math.abs(e.height-n)<=1&&(n=e.height),{x:t.offsetLeft,y:t.offsetTop,width:i,height:n}}function Xt(t,e){var i=e.getRootNode&&e.getRootNode();if(t.contains(e))return!0;if(i&&qt(i)){var n=e;do{if(n&&t.isSameNode(n))return!0;n=n.parentNode||n.host}while(n)}return!1}function Yt(t){return Wt(t).getComputedStyle(t)}function Qt(t){return["table","td","th"].indexOf(Rt(t))>=0}function Gt(t){return(($t(t)?t.ownerDocument:t.document)||window.document).documentElement}function Zt(t){return"html"===Rt(t)?t:t.assignedSlot||t.parentNode||(qt(t)?t.host:null)||Gt(t)}function Jt(t){return zt(t)&&"fixed"!==Yt(t).position?t.offsetParent:null}function te(t){for(var e=Wt(t),i=Jt(t);i&&Qt(i)&&"static"===Yt(i).position;)i=Jt(i);return i&&("html"===Rt(i)||"body"===Rt(i)&&"static"===Yt(i).position)?e:i||function(t){var e=-1!==navigator.userAgent.toLowerCase().indexOf("firefox");if(-1!==navigator.userAgent.indexOf("Trident")&&zt(t)&&"fixed"===Yt(t).position)return null;for(var i=Zt(t);zt(i)&&["html","body"].indexOf(Rt(i))<0;){var n=Yt(i);if("none"!==n.transform||"none"!==n.perspective||"paint"===n.contain||-1!==["transform","perspective"].indexOf(n.willChange)||e&&"filter"===n.willChange||e&&n.filter&&"none"!==n.filter)return i;i=i.parentNode}return null}(t)||e}function ee(t){return["top","bottom"].indexOf(t)>=0?"x":"y"}var ie=Math.max,ne=Math.min,se=Math.round;function oe(t,e,i){return ie(t,ne(e,i))}function re(t){return Object.assign({},{top:0,right:0,bottom:0,left:0},t)}function ae(t,e){return e.reduce((function(e,i){return e[i]=t,e}),{})}const le={name:"arrow",enabled:!0,phase:"main",fn:function(t){var e,i=t.state,n=t.name,s=t.options,o=i.elements.arrow,r=i.modifiersData.popperOffsets,a=Ut(i.placement),l=ee(a),c=[bt,_t].indexOf(a)>=0?"height":"width";if(o&&r){var h=function(t,e){return re("number"!=typeof(t="function"==typeof t?t(Object.assign({},e.rects,{placement:e.placement})):t)?t:ae(t,yt))}(s.padding,i),d=Kt(o),u="y"===l?mt:bt,f="y"===l?gt:_t,p=i.rects.reference[c]+i.rects.reference[l]-r[l]-i.rects.popper[c],m=r[l]-i.rects.reference[l],g=te(o),_=g?"y"===l?g.clientHeight||0:g.clientWidth||0:0,b=p/2-m/2,v=h[u],y=_-d[c]-h[f],w=_/2-d[c]/2+b,E=oe(v,w,y),A=l;i.modifiersData[n]=((e={})[A]=E,e.centerOffset=E-w,e)}},effect:function(t){var e=t.state,i=t.options.element,n=void 0===i?"[data-popper-arrow]":i;null!=n&&("string"!=typeof n||(n=e.elements.popper.querySelector(n)))&&Xt(e.elements.popper,n)&&(e.elements.arrow=n)},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function ce(t){return t.split("-")[1]}var he={top:"auto",right:"auto",bottom:"auto",left:"auto"};function de(t){var e,i=t.popper,n=t.popperRect,s=t.placement,o=t.variation,r=t.offsets,a=t.position,l=t.gpuAcceleration,c=t.adaptive,h=t.roundOffsets,d=!0===h?function(t){var e=t.x,i=t.y,n=window.devicePixelRatio||1;return{x:se(se(e*n)/n)||0,y:se(se(i*n)/n)||0}}(r):"function"==typeof h?h(r):r,u=d.x,f=void 0===u?0:u,p=d.y,m=void 0===p?0:p,g=r.hasOwnProperty("x"),_=r.hasOwnProperty("y"),b=bt,v=mt,y=window;if(c){var w=te(i),E="clientHeight",A="clientWidth";w===Wt(i)&&"static"!==Yt(w=Gt(i)).position&&"absolute"===a&&(E="scrollHeight",A="scrollWidth"),w=w,s!==mt&&(s!==bt&&s!==_t||o!==Et)||(v=gt,m-=w[E]-n.height,m*=l?1:-1),s!==bt&&(s!==mt&&s!==gt||o!==Et)||(b=_t,f-=w[A]-n.width,f*=l?1:-1)}var T,O=Object.assign({position:a},c&&he);return l?Object.assign({},O,((T={})[v]=_?"0":"",T[b]=g?"0":"",T.transform=(y.devicePixelRatio||1)<=1?"translate("+f+"px, "+m+"px)":"translate3d("+f+"px, "+m+"px, 0)",T)):Object.assign({},O,((e={})[v]=_?m+"px":"",e[b]=g?f+"px":"",e.transform="",e))}const ue={name:"computeStyles",enabled:!0,phase:"beforeWrite",fn:function(t){var e=t.state,i=t.options,n=i.gpuAcceleration,s=void 0===n||n,o=i.adaptive,r=void 0===o||o,a=i.roundOffsets,l=void 0===a||a,c={placement:Ut(e.placement),variation:ce(e.placement),popper:e.elements.popper,popperRect:e.rects.popper,gpuAcceleration:s};null!=e.modifiersData.popperOffsets&&(e.styles.popper=Object.assign({},e.styles.popper,de(Object.assign({},c,{offsets:e.modifiersData.popperOffsets,position:e.options.strategy,adaptive:r,roundOffsets:l})))),null!=e.modifiersData.arrow&&(e.styles.arrow=Object.assign({},e.styles.arrow,de(Object.assign({},c,{offsets:e.modifiersData.arrow,position:"absolute",adaptive:!1,roundOffsets:l})))),e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-placement":e.placement})},data:{}};var fe={passive:!0};const pe={name:"eventListeners",enabled:!0,phase:"write",fn:function(){},effect:function(t){var e=t.state,i=t.instance,n=t.options,s=n.scroll,o=void 0===s||s,r=n.resize,a=void 0===r||r,l=Wt(e.elements.popper),c=[].concat(e.scrollParents.reference,e.scrollParents.popper);return o&&c.forEach((function(t){t.addEventListener("scroll",i.update,fe)})),a&&l.addEventListener("resize",i.update,fe),function(){o&&c.forEach((function(t){t.removeEventListener("scroll",i.update,fe)})),a&&l.removeEventListener("resize",i.update,fe)}},data:{}};var me={left:"right",right:"left",bottom:"top",top:"bottom"};function ge(t){return t.replace(/left|right|bottom|top/g,(function(t){return me[t]}))}var _e={start:"end",end:"start"};function be(t){return t.replace(/start|end/g,(function(t){return _e[t]}))}function ve(t){var e=Wt(t);return{scrollLeft:e.pageXOffset,scrollTop:e.pageYOffset}}function ye(t){return Vt(Gt(t)).left+ve(t).scrollLeft}function we(t){var e=Yt(t),i=e.overflow,n=e.overflowX,s=e.overflowY;return/auto|scroll|overlay|hidden/.test(i+s+n)}function Ee(t){return["html","body","#document"].indexOf(Rt(t))>=0?t.ownerDocument.body:zt(t)&&we(t)?t:Ee(Zt(t))}function Ae(t,e){var i;void 0===e&&(e=[]);var n=Ee(t),s=n===(null==(i=t.ownerDocument)?void 0:i.body),o=Wt(n),r=s?[o].concat(o.visualViewport||[],we(n)?n:[]):n,a=e.concat(r);return s?a:a.concat(Ae(Zt(r)))}function Te(t){return Object.assign({},t,{left:t.x,top:t.y,right:t.x+t.width,bottom:t.y+t.height})}function Oe(t,e){return e===Tt?Te(function(t){var e=Wt(t),i=Gt(t),n=e.visualViewport,s=i.clientWidth,o=i.clientHeight,r=0,a=0;return n&&(s=n.width,o=n.height,/^((?!chrome|android).)*safari/i.test(navigator.userAgent)||(r=n.offsetLeft,a=n.offsetTop)),{width:s,height:o,x:r+ye(t),y:a}}(t)):zt(e)?function(t){var e=Vt(t);return e.top=e.top+t.clientTop,e.left=e.left+t.clientLeft,e.bottom=e.top+t.clientHeight,e.right=e.left+t.clientWidth,e.width=t.clientWidth,e.height=t.clientHeight,e.x=e.left,e.y=e.top,e}(e):Te(function(t){var e,i=Gt(t),n=ve(t),s=null==(e=t.ownerDocument)?void 0:e.body,o=ie(i.scrollWidth,i.clientWidth,s?s.scrollWidth:0,s?s.clientWidth:0),r=ie(i.scrollHeight,i.clientHeight,s?s.scrollHeight:0,s?s.clientHeight:0),a=-n.scrollLeft+ye(t),l=-n.scrollTop;return"rtl"===Yt(s||i).direction&&(a+=ie(i.clientWidth,s?s.clientWidth:0)-o),{width:o,height:r,x:a,y:l}}(Gt(t)))}function Ce(t){var e,i=t.reference,n=t.element,s=t.placement,o=s?Ut(s):null,r=s?ce(s):null,a=i.x+i.width/2-n.width/2,l=i.y+i.height/2-n.height/2;switch(o){case mt:e={x:a,y:i.y-n.height};break;case gt:e={x:a,y:i.y+i.height};break;case _t:e={x:i.x+i.width,y:l};break;case bt:e={x:i.x-n.width,y:l};break;default:e={x:i.x,y:i.y}}var c=o?ee(o):null;if(null!=c){var h="y"===c?"height":"width";switch(r){case wt:e[c]=e[c]-(i[h]/2-n[h]/2);break;case Et:e[c]=e[c]+(i[h]/2-n[h]/2)}}return e}function ke(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=void 0===n?t.placement:n,o=i.boundary,r=void 0===o?At:o,a=i.rootBoundary,l=void 0===a?Tt:a,c=i.elementContext,h=void 0===c?Ot:c,d=i.altBoundary,u=void 0!==d&&d,f=i.padding,p=void 0===f?0:f,m=re("number"!=typeof p?p:ae(p,yt)),g=h===Ot?Ct:Ot,_=t.rects.popper,b=t.elements[u?g:h],v=function(t,e,i){var n="clippingParents"===e?function(t){var e=Ae(Zt(t)),i=["absolute","fixed"].indexOf(Yt(t).position)>=0&&zt(t)?te(t):t;return $t(i)?e.filter((function(t){return $t(t)&&Xt(t,i)&&"body"!==Rt(t)})):[]}(t):[].concat(e),s=[].concat(n,[i]),o=s[0],r=s.reduce((function(e,i){var n=Oe(t,i);return e.top=ie(n.top,e.top),e.right=ne(n.right,e.right),e.bottom=ne(n.bottom,e.bottom),e.left=ie(n.left,e.left),e}),Oe(t,o));return r.width=r.right-r.left,r.height=r.bottom-r.top,r.x=r.left,r.y=r.top,r}($t(b)?b:b.contextElement||Gt(t.elements.popper),r,l),y=Vt(t.elements.reference),w=Ce({reference:y,element:_,strategy:"absolute",placement:s}),E=Te(Object.assign({},_,w)),A=h===Ot?E:y,T={top:v.top-A.top+m.top,bottom:A.bottom-v.bottom+m.bottom,left:v.left-A.left+m.left,right:A.right-v.right+m.right},O=t.modifiersData.offset;if(h===Ot&&O){var C=O[s];Object.keys(T).forEach((function(t){var e=[_t,gt].indexOf(t)>=0?1:-1,i=[mt,gt].indexOf(t)>=0?"y":"x";T[t]+=C[i]*e}))}return T}function Le(t,e){void 0===e&&(e={});var i=e,n=i.placement,s=i.boundary,o=i.rootBoundary,r=i.padding,a=i.flipVariations,l=i.allowedAutoPlacements,c=void 0===l?Lt:l,h=ce(n),d=h?a?kt:kt.filter((function(t){return ce(t)===h})):yt,u=d.filter((function(t){return c.indexOf(t)>=0}));0===u.length&&(u=d);var f=u.reduce((function(e,i){return e[i]=ke(t,{placement:i,boundary:s,rootBoundary:o,padding:r})[Ut(i)],e}),{});return Object.keys(f).sort((function(t,e){return f[t]-f[e]}))}const xe={name:"flip",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name;if(!e.modifiersData[n]._skip){for(var s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0===r||r,l=i.fallbackPlacements,c=i.padding,h=i.boundary,d=i.rootBoundary,u=i.altBoundary,f=i.flipVariations,p=void 0===f||f,m=i.allowedAutoPlacements,g=e.options.placement,_=Ut(g),b=l||(_!==g&&p?function(t){if(Ut(t)===vt)return[];var e=ge(t);return[be(t),e,be(e)]}(g):[ge(g)]),v=[g].concat(b).reduce((function(t,i){return t.concat(Ut(i)===vt?Le(e,{placement:i,boundary:h,rootBoundary:d,padding:c,flipVariations:p,allowedAutoPlacements:m}):i)}),[]),y=e.rects.reference,w=e.rects.popper,E=new Map,A=!0,T=v[0],O=0;O<v.length;O++){var C=v[O],k=Ut(C),L=ce(C)===wt,x=[mt,gt].indexOf(k)>=0,D=x?"width":"height",S=ke(e,{placement:C,boundary:h,rootBoundary:d,altBoundary:u,padding:c}),N=x?L?_t:bt:L?gt:mt;y[D]>w[D]&&(N=ge(N));var I=ge(N),P=[];if(o&&P.push(S[k]<=0),a&&P.push(S[N]<=0,S[I]<=0),P.every((function(t){return t}))){T=C,A=!1;break}E.set(C,P)}if(A)for(var j=function(t){var e=v.find((function(e){var i=E.get(e);if(i)return i.slice(0,t).every((function(t){return t}))}));if(e)return T=e,"break"},M=p?3:1;M>0&&"break"!==j(M);M--);e.placement!==T&&(e.modifiersData[n]._skip=!0,e.placement=T,e.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}};function De(t,e,i){return void 0===i&&(i={x:0,y:0}),{top:t.top-e.height-i.y,right:t.right-e.width+i.x,bottom:t.bottom-e.height+i.y,left:t.left-e.width-i.x}}function Se(t){return[mt,_t,gt,bt].some((function(e){return t[e]>=0}))}const Ne={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:function(t){var e=t.state,i=t.name,n=e.rects.reference,s=e.rects.popper,o=e.modifiersData.preventOverflow,r=ke(e,{elementContext:"reference"}),a=ke(e,{altBoundary:!0}),l=De(r,n),c=De(a,s,o),h=Se(l),d=Se(c);e.modifiersData[i]={referenceClippingOffsets:l,popperEscapeOffsets:c,isReferenceHidden:h,hasPopperEscaped:d},e.attributes.popper=Object.assign({},e.attributes.popper,{"data-popper-reference-hidden":h,"data-popper-escaped":d})}},Ie={name:"offset",enabled:!0,phase:"main",requires:["popperOffsets"],fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.offset,o=void 0===s?[0,0]:s,r=Lt.reduce((function(t,i){return t[i]=function(t,e,i){var n=Ut(t),s=[bt,mt].indexOf(n)>=0?-1:1,o="function"==typeof i?i(Object.assign({},e,{placement:t})):i,r=o[0],a=o[1];return r=r||0,a=(a||0)*s,[bt,_t].indexOf(n)>=0?{x:a,y:r}:{x:r,y:a}}(i,e.rects,o),t}),{}),a=r[e.placement],l=a.x,c=a.y;null!=e.modifiersData.popperOffsets&&(e.modifiersData.popperOffsets.x+=l,e.modifiersData.popperOffsets.y+=c),e.modifiersData[n]=r}},Pe={name:"popperOffsets",enabled:!0,phase:"read",fn:function(t){var e=t.state,i=t.name;e.modifiersData[i]=Ce({reference:e.rects.reference,element:e.rects.popper,strategy:"absolute",placement:e.placement})},data:{}},je={name:"preventOverflow",enabled:!0,phase:"main",fn:function(t){var e=t.state,i=t.options,n=t.name,s=i.mainAxis,o=void 0===s||s,r=i.altAxis,a=void 0!==r&&r,l=i.boundary,c=i.rootBoundary,h=i.altBoundary,d=i.padding,u=i.tether,f=void 0===u||u,p=i.tetherOffset,m=void 0===p?0:p,g=ke(e,{boundary:l,rootBoundary:c,padding:d,altBoundary:h}),_=Ut(e.placement),b=ce(e.placement),v=!b,y=ee(_),w="x"===y?"y":"x",E=e.modifiersData.popperOffsets,A=e.rects.reference,T=e.rects.popper,O="function"==typeof m?m(Object.assign({},e.rects,{placement:e.placement})):m,C={x:0,y:0};if(E){if(o||a){var k="y"===y?mt:bt,L="y"===y?gt:_t,x="y"===y?"height":"width",D=E[y],S=E[y]+g[k],N=E[y]-g[L],I=f?-T[x]/2:0,P=b===wt?A[x]:T[x],j=b===wt?-T[x]:-A[x],M=e.elements.arrow,H=f&&M?Kt(M):{width:0,height:0},B=e.modifiersData["arrow#persistent"]?e.modifiersData["arrow#persistent"].padding:{top:0,right:0,bottom:0,left:0},R=B[k],W=B[L],$=oe(0,A[x],H[x]),z=v?A[x]/2-I-$-R-O:P-$-R-O,q=v?-A[x]/2+I+$+W+O:j+$+W+O,F=e.elements.arrow&&te(e.elements.arrow),U=F?"y"===y?F.clientTop||0:F.clientLeft||0:0,V=e.modifiersData.offset?e.modifiersData.offset[e.placement][y]:0,K=E[y]+z-V-U,X=E[y]+q-V;if(o){var Y=oe(f?ne(S,K):S,D,f?ie(N,X):N);E[y]=Y,C[y]=Y-D}if(a){var Q="x"===y?mt:bt,G="x"===y?gt:_t,Z=E[w],J=Z+g[Q],tt=Z-g[G],et=oe(f?ne(J,K):J,Z,f?ie(tt,X):tt);E[w]=et,C[w]=et-Z}}e.modifiersData[n]=C}},requiresIfExists:["offset"]};function Me(t,e,i){void 0===i&&(i=!1);var n=zt(e);zt(e)&&function(t){var e=t.getBoundingClientRect();e.width,t.offsetWidth,e.height,t.offsetHeight}(e);var s,o,r=Gt(e),a=Vt(t),l={scrollLeft:0,scrollTop:0},c={x:0,y:0};return(n||!n&&!i)&&(("body"!==Rt(e)||we(r))&&(l=(s=e)!==Wt(s)&&zt(s)?{scrollLeft:(o=s).scrollLeft,scrollTop:o.scrollTop}:ve(s)),zt(e)?((c=Vt(e)).x+=e.clientLeft,c.y+=e.clientTop):r&&(c.x=ye(r))),{x:a.left+l.scrollLeft-c.x,y:a.top+l.scrollTop-c.y,width:a.width,height:a.height}}function He(t){var e=new Map,i=new Set,n=[];function s(t){i.add(t.name),[].concat(t.requires||[],t.requiresIfExists||[]).forEach((function(t){if(!i.has(t)){var n=e.get(t);n&&s(n)}})),n.push(t)}return t.forEach((function(t){e.set(t.name,t)})),t.forEach((function(t){i.has(t.name)||s(t)})),n}var Be={placement:"bottom",modifiers:[],strategy:"absolute"};function Re(){for(var t=arguments.length,e=new Array(t),i=0;i<t;i++)e[i]=arguments[i];return!e.some((function(t){return!(t&&"function"==typeof t.getBoundingClientRect)}))}function We(t){void 0===t&&(t={});var e=t,i=e.defaultModifiers,n=void 0===i?[]:i,s=e.defaultOptions,o=void 0===s?Be:s;return function(t,e,i){void 0===i&&(i=o);var s,r,a={placement:"bottom",orderedModifiers:[],options:Object.assign({},Be,o),modifiersData:{},elements:{reference:t,popper:e},attributes:{},styles:{}},l=[],c=!1,h={state:a,setOptions:function(i){var s="function"==typeof i?i(a.options):i;d(),a.options=Object.assign({},o,a.options,s),a.scrollParents={reference:$t(t)?Ae(t):t.contextElement?Ae(t.contextElement):[],popper:Ae(e)};var r,c,u=function(t){var e=He(t);return Bt.reduce((function(t,i){return t.concat(e.filter((function(t){return t.phase===i})))}),[])}((r=[].concat(n,a.options.modifiers),c=r.reduce((function(t,e){var i=t[e.name];return t[e.name]=i?Object.assign({},i,e,{options:Object.assign({},i.options,e.options),data:Object.assign({},i.data,e.data)}):e,t}),{}),Object.keys(c).map((function(t){return c[t]}))));return a.orderedModifiers=u.filter((function(t){return t.enabled})),a.orderedModifiers.forEach((function(t){var e=t.name,i=t.options,n=void 0===i?{}:i,s=t.effect;if("function"==typeof s){var o=s({state:a,name:e,instance:h,options:n});l.push(o||function(){})}})),h.update()},forceUpdate:function(){if(!c){var t=a.elements,e=t.reference,i=t.popper;if(Re(e,i)){a.rects={reference:Me(e,te(i),"fixed"===a.options.strategy),popper:Kt(i)},a.reset=!1,a.placement=a.options.placement,a.orderedModifiers.forEach((function(t){return a.modifiersData[t.name]=Object.assign({},t.data)}));for(var n=0;n<a.orderedModifiers.length;n++)if(!0!==a.reset){var s=a.orderedModifiers[n],o=s.fn,r=s.options,l=void 0===r?{}:r,d=s.name;"function"==typeof o&&(a=o({state:a,options:l,name:d,instance:h})||a)}else a.reset=!1,n=-1}}},update:(s=function(){return new Promise((function(t){h.forceUpdate(),t(a)}))},function(){return r||(r=new Promise((function(t){Promise.resolve().then((function(){r=void 0,t(s())}))}))),r}),destroy:function(){d(),c=!0}};if(!Re(t,e))return h;function d(){l.forEach((function(t){return t()})),l=[]}return h.setOptions(i).then((function(t){!c&&i.onFirstUpdate&&i.onFirstUpdate(t)})),h}}var $e=We(),ze=We({defaultModifiers:[pe,Pe,ue,Ft]}),qe=We({defaultModifiers:[pe,Pe,ue,Ft,Ie,xe,je,le,Ne]});const Fe=Object.freeze({__proto__:null,popperGenerator:We,detectOverflow:ke,createPopperBase:$e,createPopper:qe,createPopperLite:ze,top:mt,bottom:gt,right:_t,left:bt,auto:vt,basePlacements:yt,start:wt,end:Et,clippingParents:At,viewport:Tt,popper:Ot,reference:Ct,variationPlacements:kt,placements:Lt,beforeRead:xt,read:Dt,afterRead:St,beforeMain:Nt,main:It,afterMain:Pt,beforeWrite:jt,write:Mt,afterWrite:Ht,modifierPhases:Bt,applyStyles:Ft,arrow:le,computeStyles:ue,eventListeners:pe,flip:xe,hide:Ne,offset:Ie,popperOffsets:Pe,preventOverflow:je}),Ue="dropdown",Ve="Escape",Ke="Space",Xe="ArrowUp",Ye="ArrowDown",Qe=new RegExp("ArrowUp|ArrowDown|Escape"),Ge="click.bs.dropdown.data-api",Ze="keydown.bs.dropdown.data-api",Je="show",ti='[data-bs-toggle="dropdown"]',ei=".dropdown-menu",ii=m()?"top-end":"top-start",ni=m()?"top-start":"top-end",si=m()?"bottom-end":"bottom-start",oi=m()?"bottom-start":"bottom-end",ri=m()?"left-start":"right-start",ai=m()?"right-start":"left-start",li={offset:[0,2],boundary:"clippingParents",reference:"toggle",display:"dynamic",popperConfig:null,autoClose:!0},ci={offset:"(array|string|function)",boundary:"(string|element)",reference:"(string|element|object)",display:"string",popperConfig:"(null|object|function)",autoClose:"(boolean|string)"};class hi extends B{constructor(t,e){super(t),this._popper=null,this._config=this._getConfig(e),this._menu=this._getMenuElement(),this._inNavbar=this._detectNavbar()}static get Default(){return li}static get DefaultType(){return ci}static get NAME(){return Ue}toggle(){return this._isShown()?this.hide():this.show()}show(){if(c(this._element)||this._isShown(this._menu))return;const t={relatedTarget:this._element};if(j.trigger(this._element,"show.bs.dropdown",t).defaultPrevented)return;const e=hi.getParentFromElement(this._element);this._inNavbar?U.setDataAttribute(this._menu,"popper","none"):this._createPopper(e),"ontouchstart"in document.documentElement&&!e.closest(".navbar-nav")&&[].concat(...document.body.children).forEach((t=>j.on(t,"mouseover",d))),this._element.focus(),this._element.setAttribute("aria-expanded",!0),this._menu.classList.add(Je),this._element.classList.add(Je),j.trigger(this._element,"shown.bs.dropdown",t)}hide(){if(c(this._element)||!this._isShown(this._menu))return;const t={relatedTarget:this._element};this._completeHide(t)}dispose(){this._popper&&this._popper.destroy(),super.dispose()}update(){this._inNavbar=this._detectNavbar(),this._popper&&this._popper.update()}_completeHide(t){j.trigger(this._element,"hide.bs.dropdown",t).defaultPrevented||("ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach((t=>j.off(t,"mouseover",d))),this._popper&&this._popper.destroy(),this._menu.classList.remove(Je),this._element.classList.remove(Je),this._element.setAttribute("aria-expanded","false"),U.removeDataAttribute(this._menu,"popper"),j.trigger(this._element,"hidden.bs.dropdown",t))}_getConfig(t){if(t={...this.constructor.Default,...U.getDataAttributes(this._element),...t},a(Ue,t,this.constructor.DefaultType),"object"==typeof t.reference&&!o(t.reference)&&"function"!=typeof t.reference.getBoundingClientRect)throw new TypeError(`${Ue.toUpperCase()}: Option "reference" provided type "object" without a required "getBoundingClientRect" method.`);return t}_createPopper(t){if(void 0===Fe)throw new TypeError("Bootstrap's dropdowns require Popper (https://popper.js.org)");let e=this._element;"parent"===this._config.reference?e=t:o(this._config.reference)?e=r(this._config.reference):"object"==typeof this._config.reference&&(e=this._config.reference);const i=this._getPopperConfig(),n=i.modifiers.find((t=>"applyStyles"===t.name&&!1===t.enabled));this._popper=qe(e,this._menu,i),n&&U.setDataAttribute(this._menu,"popper","static")}_isShown(t=this._element){return t.classList.contains(Je)}_getMenuElement(){return V.next(this._element,ei)[0]}_getPlacement(){const t=this._element.parentNode;if(t.classList.contains("dropend"))return ri;if(t.classList.contains("dropstart"))return ai;const e="end"===getComputedStyle(this._menu).getPropertyValue("--bs-position").trim();return t.classList.contains("dropup")?e?ni:ii:e?oi:si}_detectNavbar(){return null!==this._element.closest(".navbar")}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_getPopperConfig(){const t={placement:this._getPlacement(),modifiers:[{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"offset",options:{offset:this._getOffset()}}]};return"static"===this._config.display&&(t.modifiers=[{name:"applyStyles",enabled:!1}]),{...t,..."function"==typeof this._config.popperConfig?this._config.popperConfig(t):this._config.popperConfig}}_selectMenuItem({key:t,target:e}){const i=V.find(".dropdown-menu .dropdown-item:not(.disabled):not(:disabled)",this._menu).filter(l);i.length&&v(i,e,t===Ye,!i.includes(e)).focus()}static jQueryInterface(t){return this.each((function(){const e=hi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}static clearMenus(t){if(t&&(2===t.button||"keyup"===t.type&&"Tab"!==t.key))return;const e=V.find(ti);for(let i=0,n=e.length;i<n;i++){const n=hi.getInstance(e[i]);if(!n||!1===n._config.autoClose)continue;if(!n._isShown())continue;const s={relatedTarget:n._element};if(t){const e=t.composedPath(),i=e.includes(n._menu);if(e.includes(n._element)||"inside"===n._config.autoClose&&!i||"outside"===n._config.autoClose&&i)continue;if(n._menu.contains(t.target)&&("keyup"===t.type&&"Tab"===t.key||/input|select|option|textarea|form/i.test(t.target.tagName)))continue;"click"===t.type&&(s.clickEvent=t)}n._completeHide(s)}}static getParentFromElement(t){return n(t)||t.parentNode}static dataApiKeydownHandler(t){if(/input|textarea/i.test(t.target.tagName)?t.key===Ke||t.key!==Ve&&(t.key!==Ye&&t.key!==Xe||t.target.closest(ei)):!Qe.test(t.key))return;const e=this.classList.contains(Je);if(!e&&t.key===Ve)return;if(t.preventDefault(),t.stopPropagation(),c(this))return;const i=this.matches(ti)?this:V.prev(this,ti)[0],n=hi.getOrCreateInstance(i);if(t.key!==Ve)return t.key===Xe||t.key===Ye?(e||n.show(),void n._selectMenuItem(t)):void(e&&t.key!==Ke||hi.clearMenus());n.hide()}}j.on(document,Ze,ti,hi.dataApiKeydownHandler),j.on(document,Ze,ei,hi.dataApiKeydownHandler),j.on(document,Ge,hi.clearMenus),j.on(document,"keyup.bs.dropdown.data-api",hi.clearMenus),j.on(document,Ge,ti,(function(t){t.preventDefault(),hi.getOrCreateInstance(this).toggle()})),g(hi);const di=".fixed-top, .fixed-bottom, .is-fixed, .sticky-top",ui=".sticky-top";class fi{constructor(){this._element=document.body}getWidth(){const t=document.documentElement.clientWidth;return Math.abs(window.innerWidth-t)}hide(){const t=this.getWidth();this._disableOverFlow(),this._setElementAttributes(this._element,"paddingRight",(e=>e+t)),this._setElementAttributes(di,"paddingRight",(e=>e+t)),this._setElementAttributes(ui,"marginRight",(e=>e-t))}_disableOverFlow(){this._saveInitialAttribute(this._element,"overflow"),this._element.style.overflow="hidden"}_setElementAttributes(t,e,i){const n=this.getWidth();this._applyManipulationCallback(t,(t=>{if(t!==this._element&&window.innerWidth>t.clientWidth+n)return;this._saveInitialAttribute(t,e);const s=window.getComputedStyle(t)[e];t.style[e]=`${i(Number.parseFloat(s))}px`}))}reset(){this._resetElementAttributes(this._element,"overflow"),this._resetElementAttributes(this._element,"paddingRight"),this._resetElementAttributes(di,"paddingRight"),this._resetElementAttributes(ui,"marginRight")}_saveInitialAttribute(t,e){const i=t.style[e];i&&U.setDataAttribute(t,e,i)}_resetElementAttributes(t,e){this._applyManipulationCallback(t,(t=>{const i=U.getDataAttribute(t,e);void 0===i?t.style.removeProperty(e):(U.removeDataAttribute(t,e),t.style[e]=i)}))}_applyManipulationCallback(t,e){o(t)?e(t):V.find(t,this._element).forEach(e)}isOverflowing(){return this.getWidth()>0}}const pi={className:"modal-backdrop",isVisible:!0,isAnimated:!1,rootElement:"body",clickCallback:null},mi={className:"string",isVisible:"boolean",isAnimated:"boolean",rootElement:"(element|string)",clickCallback:"(function|null)"},gi="show",_i="mousedown.bs.backdrop";class bi{constructor(t){this._config=this._getConfig(t),this._isAppended=!1,this._element=null}show(t){this._config.isVisible?(this._append(),this._config.isAnimated&&u(this._getElement()),this._getElement().classList.add(gi),this._emulateAnimation((()=>{_(t)}))):_(t)}hide(t){this._config.isVisible?(this._getElement().classList.remove(gi),this._emulateAnimation((()=>{this.dispose(),_(t)}))):_(t)}_getElement(){if(!this._element){const t=document.createElement("div");t.className=this._config.className,this._config.isAnimated&&t.classList.add("fade"),this._element=t}return this._element}_getConfig(t){return(t={...pi,..."object"==typeof t?t:{}}).rootElement=r(t.rootElement),a("backdrop",t,mi),t}_append(){this._isAppended||(this._config.rootElement.append(this._getElement()),j.on(this._getElement(),_i,(()=>{_(this._config.clickCallback)})),this._isAppended=!0)}dispose(){this._isAppended&&(j.off(this._element,_i),this._element.remove(),this._isAppended=!1)}_emulateAnimation(t){b(t,this._getElement(),this._config.isAnimated)}}const vi={trapElement:null,autofocus:!0},yi={trapElement:"element",autofocus:"boolean"},wi=".bs.focustrap",Ei="backward";class Ai{constructor(t){this._config=this._getConfig(t),this._isActive=!1,this._lastTabNavDirection=null}activate(){const{trapElement:t,autofocus:e}=this._config;this._isActive||(e&&t.focus(),j.off(document,wi),j.on(document,"focusin.bs.focustrap",(t=>this._handleFocusin(t))),j.on(document,"keydown.tab.bs.focustrap",(t=>this._handleKeydown(t))),this._isActive=!0)}deactivate(){this._isActive&&(this._isActive=!1,j.off(document,wi))}_handleFocusin(t){const{target:e}=t,{trapElement:i}=this._config;if(e===document||e===i||i.contains(e))return;const n=V.focusableChildren(i);0===n.length?i.focus():this._lastTabNavDirection===Ei?n[n.length-1].focus():n[0].focus()}_handleKeydown(t){"Tab"===t.key&&(this._lastTabNavDirection=t.shiftKey?Ei:"forward")}_getConfig(t){return t={...vi,..."object"==typeof t?t:{}},a("focustrap",t,yi),t}}const Ti="modal",Oi="Escape",Ci={backdrop:!0,keyboard:!0,focus:!0},ki={backdrop:"(boolean|string)",keyboard:"boolean",focus:"boolean"},Li="hidden.bs.modal",xi="show.bs.modal",Di="resize.bs.modal",Si="click.dismiss.bs.modal",Ni="keydown.dismiss.bs.modal",Ii="mousedown.dismiss.bs.modal",Pi="modal-open",ji="show",Mi="modal-static";class Hi extends B{constructor(t,e){super(t),this._config=this._getConfig(e),this._dialog=V.findOne(".modal-dialog",this._element),this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._isShown=!1,this._ignoreBackdropClick=!1,this._isTransitioning=!1,this._scrollBar=new fi}static get Default(){return Ci}static get NAME(){return Ti}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||this._isTransitioning||j.trigger(this._element,xi,{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._isAnimated()&&(this._isTransitioning=!0),this._scrollBar.hide(),document.body.classList.add(Pi),this._adjustDialog(),this._setEscapeEvent(),this._setResizeEvent(),j.on(this._dialog,Ii,(()=>{j.one(this._element,"mouseup.dismiss.bs.modal",(t=>{t.target===this._element&&(this._ignoreBackdropClick=!0)}))})),this._showBackdrop((()=>this._showElement(t))))}hide(){if(!this._isShown||this._isTransitioning)return;if(j.trigger(this._element,"hide.bs.modal").defaultPrevented)return;this._isShown=!1;const t=this._isAnimated();t&&(this._isTransitioning=!0),this._setEscapeEvent(),this._setResizeEvent(),this._focustrap.deactivate(),this._element.classList.remove(ji),j.off(this._element,Si),j.off(this._dialog,Ii),this._queueCallback((()=>this._hideModal()),this._element,t)}dispose(){[window,this._dialog].forEach((t=>j.off(t,".bs.modal"))),this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}handleUpdate(){this._adjustDialog()}_initializeBackDrop(){return new bi({isVisible:Boolean(this._config.backdrop),isAnimated:this._isAnimated()})}_initializeFocusTrap(){return new Ai({trapElement:this._element})}_getConfig(t){return t={...Ci,...U.getDataAttributes(this._element),..."object"==typeof t?t:{}},a(Ti,t,ki),t}_showElement(t){const e=this._isAnimated(),i=V.findOne(".modal-body",this._dialog);this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE||document.body.append(this._element),this._element.style.display="block",this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.scrollTop=0,i&&(i.scrollTop=0),e&&u(this._element),this._element.classList.add(ji),this._queueCallback((()=>{this._config.focus&&this._focustrap.activate(),this._isTransitioning=!1,j.trigger(this._element,"shown.bs.modal",{relatedTarget:t})}),this._dialog,e)}_setEscapeEvent(){this._isShown?j.on(this._element,Ni,(t=>{this._config.keyboard&&t.key===Oi?(t.preventDefault(),this.hide()):this._config.keyboard||t.key!==Oi||this._triggerBackdropTransition()})):j.off(this._element,Ni)}_setResizeEvent(){this._isShown?j.on(window,Di,(()=>this._adjustDialog())):j.off(window,Di)}_hideModal(){this._element.style.display="none",this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._isTransitioning=!1,this._backdrop.hide((()=>{document.body.classList.remove(Pi),this._resetAdjustments(),this._scrollBar.reset(),j.trigger(this._element,Li)}))}_showBackdrop(t){j.on(this._element,Si,(t=>{this._ignoreBackdropClick?this._ignoreBackdropClick=!1:t.target===t.currentTarget&&(!0===this._config.backdrop?this.hide():"static"===this._config.backdrop&&this._triggerBackdropTransition())})),this._backdrop.show(t)}_isAnimated(){return this._element.classList.contains("fade")}_triggerBackdropTransition(){if(j.trigger(this._element,"hidePrevented.bs.modal").defaultPrevented)return;const{classList:t,scrollHeight:e,style:i}=this._element,n=e>document.documentElement.clientHeight;!n&&"hidden"===i.overflowY||t.contains(Mi)||(n||(i.overflowY="hidden"),t.add(Mi),this._queueCallback((()=>{t.remove(Mi),n||this._queueCallback((()=>{i.overflowY=""}),this._dialog)}),this._dialog),this._element.focus())}_adjustDialog(){const t=this._element.scrollHeight>document.documentElement.clientHeight,e=this._scrollBar.getWidth(),i=e>0;(!i&&t&&!m()||i&&!t&&m())&&(this._element.style.paddingLeft=`${e}px`),(i&&!t&&!m()||!i&&t&&m())&&(this._element.style.paddingRight=`${e}px`)}_resetAdjustments(){this._element.style.paddingLeft="",this._element.style.paddingRight=""}static jQueryInterface(t,e){return this.each((function(){const i=Hi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===i[t])throw new TypeError(`No method named "${t}"`);i[t](e)}}))}}j.on(document,"click.bs.modal.data-api",'[data-bs-toggle="modal"]',(function(t){const e=n(this);["A","AREA"].includes(this.tagName)&&t.preventDefault(),j.one(e,xi,(t=>{t.defaultPrevented||j.one(e,Li,(()=>{l(this)&&this.focus()}))}));const i=V.findOne(".modal.show");i&&Hi.getInstance(i).hide(),Hi.getOrCreateInstance(e).toggle(this)})),R(Hi),g(Hi);const Bi="offcanvas",Ri={backdrop:!0,keyboard:!0,scroll:!1},Wi={backdrop:"boolean",keyboard:"boolean",scroll:"boolean"},$i="show",zi=".offcanvas.show",qi="hidden.bs.offcanvas";class Fi extends B{constructor(t,e){super(t),this._config=this._getConfig(e),this._isShown=!1,this._backdrop=this._initializeBackDrop(),this._focustrap=this._initializeFocusTrap(),this._addEventListeners()}static get NAME(){return Bi}static get Default(){return Ri}toggle(t){return this._isShown?this.hide():this.show(t)}show(t){this._isShown||j.trigger(this._element,"show.bs.offcanvas",{relatedTarget:t}).defaultPrevented||(this._isShown=!0,this._element.style.visibility="visible",this._backdrop.show(),this._config.scroll||(new fi).hide(),this._element.removeAttribute("aria-hidden"),this._element.setAttribute("aria-modal",!0),this._element.setAttribute("role","dialog"),this._element.classList.add($i),this._queueCallback((()=>{this._config.scroll||this._focustrap.activate(),j.trigger(this._element,"shown.bs.offcanvas",{relatedTarget:t})}),this._element,!0))}hide(){this._isShown&&(j.trigger(this._element,"hide.bs.offcanvas").defaultPrevented||(this._focustrap.deactivate(),this._element.blur(),this._isShown=!1,this._element.classList.remove($i),this._backdrop.hide(),this._queueCallback((()=>{this._element.setAttribute("aria-hidden",!0),this._element.removeAttribute("aria-modal"),this._element.removeAttribute("role"),this._element.style.visibility="hidden",this._config.scroll||(new fi).reset(),j.trigger(this._element,qi)}),this._element,!0)))}dispose(){this._backdrop.dispose(),this._focustrap.deactivate(),super.dispose()}_getConfig(t){return t={...Ri,...U.getDataAttributes(this._element),..."object"==typeof t?t:{}},a(Bi,t,Wi),t}_initializeBackDrop(){return new bi({className:"offcanvas-backdrop",isVisible:this._config.backdrop,isAnimated:!0,rootElement:this._element.parentNode,clickCallback:()=>this.hide()})}_initializeFocusTrap(){return new Ai({trapElement:this._element})}_addEventListeners(){j.on(this._element,"keydown.dismiss.bs.offcanvas",(t=>{this._config.keyboard&&"Escape"===t.key&&this.hide()}))}static jQueryInterface(t){return this.each((function(){const e=Fi.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t]||t.startsWith("_")||"constructor"===t)throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}j.on(document,"click.bs.offcanvas.data-api",'[data-bs-toggle="offcanvas"]',(function(t){const e=n(this);if(["A","AREA"].includes(this.tagName)&&t.preventDefault(),c(this))return;j.one(e,qi,(()=>{l(this)&&this.focus()}));const i=V.findOne(zi);i&&i!==e&&Fi.getInstance(i).hide(),Fi.getOrCreateInstance(e).toggle(this)})),j.on(window,"load.bs.offcanvas.data-api",(()=>V.find(zi).forEach((t=>Fi.getOrCreateInstance(t).show())))),R(Fi),g(Fi);const Ui=new Set(["background","cite","href","itemtype","longdesc","poster","src","xlink:href"]),Vi=/^(?:(?:https?|mailto|ftp|tel|file|sms):|[^#&/:?]*(?:[#/?]|$))/i,Ki=/^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[\d+/a-z]+=*$/i,Xi=(t,e)=>{const i=t.nodeName.toLowerCase();if(e.includes(i))return!Ui.has(i)||Boolean(Vi.test(t.nodeValue)||Ki.test(t.nodeValue));const n=e.filter((t=>t instanceof RegExp));for(let t=0,e=n.length;t<e;t++)if(n[t].test(i))return!0;return!1};function Yi(t,e,i){if(!t.length)return t;if(i&&"function"==typeof i)return i(t);const n=(new window.DOMParser).parseFromString(t,"text/html"),s=[].concat(...n.body.querySelectorAll("*"));for(let t=0,i=s.length;t<i;t++){const i=s[t],n=i.nodeName.toLowerCase();if(!Object.keys(e).includes(n)){i.remove();continue}const o=[].concat(...i.attributes),r=[].concat(e["*"]||[],e[n]||[]);o.forEach((t=>{Xi(t,r)||i.removeAttribute(t.nodeName)}))}return n.body.innerHTML}const Qi="tooltip",Gi=new Set(["sanitize","allowList","sanitizeFn"]),Zi={animation:"boolean",template:"string",title:"(string|element|function)",trigger:"string",delay:"(number|object)",html:"boolean",selector:"(string|boolean)",placement:"(string|function)",offset:"(array|string|function)",container:"(string|element|boolean)",fallbackPlacements:"array",boundary:"(string|element)",customClass:"(string|function)",sanitize:"boolean",sanitizeFn:"(null|function)",allowList:"object",popperConfig:"(null|object|function)"},Ji={AUTO:"auto",TOP:"top",RIGHT:m()?"left":"right",BOTTOM:"bottom",LEFT:m()?"right":"left"},tn={animation:!0,template:'<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:[0,0],container:!1,fallbackPlacements:["top","right","bottom","left"],boundary:"clippingParents",customClass:"",sanitize:!0,sanitizeFn:null,allowList:{"*":["class","dir","id","lang","role",/^aria-[\w-]*$/i],a:["target","href","title","rel"],area:[],b:[],br:[],col:[],code:[],div:[],em:[],hr:[],h1:[],h2:[],h3:[],h4:[],h5:[],h6:[],i:[],img:["src","srcset","alt","title","width","height"],li:[],ol:[],p:[],pre:[],s:[],small:[],span:[],sub:[],sup:[],strong:[],u:[],ul:[]},popperConfig:null},en={HIDE:"hide.bs.tooltip",HIDDEN:"hidden.bs.tooltip",SHOW:"show.bs.tooltip",SHOWN:"shown.bs.tooltip",INSERTED:"inserted.bs.tooltip",CLICK:"click.bs.tooltip",FOCUSIN:"focusin.bs.tooltip",FOCUSOUT:"focusout.bs.tooltip",MOUSEENTER:"mouseenter.bs.tooltip",MOUSELEAVE:"mouseleave.bs.tooltip"},nn="fade",sn="show",on="show",rn="out",an=".tooltip-inner",ln=".modal",cn="hide.bs.modal",hn="hover",dn="focus";class un extends B{constructor(t,e){if(void 0===Fe)throw new TypeError("Bootstrap's tooltips require Popper (https://popper.js.org)");super(t),this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._popper=null,this._config=this._getConfig(e),this.tip=null,this._setListeners()}static get Default(){return tn}static get NAME(){return Qi}static get Event(){return en}static get DefaultType(){return Zi}enable(){this._isEnabled=!0}disable(){this._isEnabled=!1}toggleEnabled(){this._isEnabled=!this._isEnabled}toggle(t){if(this._isEnabled)if(t){const e=this._initializeOnDelegatedTarget(t);e._activeTrigger.click=!e._activeTrigger.click,e._isWithActiveTrigger()?e._enter(null,e):e._leave(null,e)}else{if(this.getTipElement().classList.contains(sn))return void this._leave(null,this);this._enter(null,this)}}dispose(){clearTimeout(this._timeout),j.off(this._element.closest(ln),cn,this._hideModalHandler),this.tip&&this.tip.remove(),this._disposePopper(),super.dispose()}show(){if("none"===this._element.style.display)throw new Error("Please use show on visible elements");if(!this.isWithContent()||!this._isEnabled)return;const t=j.trigger(this._element,this.constructor.Event.SHOW),e=h(this._element),i=null===e?this._element.ownerDocument.documentElement.contains(this._element):e.contains(this._element);if(t.defaultPrevented||!i)return;"tooltip"===this.constructor.NAME&&this.tip&&this.getTitle()!==this.tip.querySelector(an).innerHTML&&(this._disposePopper(),this.tip.remove(),this.tip=null);const n=this.getTipElement(),s=(t=>{do{t+=Math.floor(1e6*Math.random())}while(document.getElementById(t));return t})(this.constructor.NAME);n.setAttribute("id",s),this._element.setAttribute("aria-describedby",s),this._config.animation&&n.classList.add(nn);const o="function"==typeof this._config.placement?this._config.placement.call(this,n,this._element):this._config.placement,r=this._getAttachment(o);this._addAttachmentClass(r);const{container:a}=this._config;H.set(n,this.constructor.DATA_KEY,this),this._element.ownerDocument.documentElement.contains(this.tip)||(a.append(n),j.trigger(this._element,this.constructor.Event.INSERTED)),this._popper?this._popper.update():this._popper=qe(this._element,n,this._getPopperConfig(r)),n.classList.add(sn);const l=this._resolvePossibleFunction(this._config.customClass);l&&n.classList.add(...l.split(" ")),"ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach((t=>{j.on(t,"mouseover",d)}));const c=this.tip.classList.contains(nn);this._queueCallback((()=>{const t=this._hoverState;this._hoverState=null,j.trigger(this._element,this.constructor.Event.SHOWN),t===rn&&this._leave(null,this)}),this.tip,c)}hide(){if(!this._popper)return;const t=this.getTipElement();if(j.trigger(this._element,this.constructor.Event.HIDE).defaultPrevented)return;t.classList.remove(sn),"ontouchstart"in document.documentElement&&[].concat(...document.body.children).forEach((t=>j.off(t,"mouseover",d))),this._activeTrigger.click=!1,this._activeTrigger.focus=!1,this._activeTrigger.hover=!1;const e=this.tip.classList.contains(nn);this._queueCallback((()=>{this._isWithActiveTrigger()||(this._hoverState!==on&&t.remove(),this._cleanTipClass(),this._element.removeAttribute("aria-describedby"),j.trigger(this._element,this.constructor.Event.HIDDEN),this._disposePopper())}),this.tip,e),this._hoverState=""}update(){null!==this._popper&&this._popper.update()}isWithContent(){return Boolean(this.getTitle())}getTipElement(){if(this.tip)return this.tip;const t=document.createElement("div");t.innerHTML=this._config.template;const e=t.children[0];return this.setContent(e),e.classList.remove(nn,sn),this.tip=e,this.tip}setContent(t){this._sanitizeAndSetContent(t,this.getTitle(),an)}_sanitizeAndSetContent(t,e,i){const n=V.findOne(i,t);e||!n?this.setElementContent(n,e):n.remove()}setElementContent(t,e){if(null!==t)return o(e)?(e=r(e),void(this._config.html?e.parentNode!==t&&(t.innerHTML="",t.append(e)):t.textContent=e.textContent)):void(this._config.html?(this._config.sanitize&&(e=Yi(e,this._config.allowList,this._config.sanitizeFn)),t.innerHTML=e):t.textContent=e)}getTitle(){const t=this._element.getAttribute("data-bs-original-title")||this._config.title;return this._resolvePossibleFunction(t)}updateAttachment(t){return"right"===t?"end":"left"===t?"start":t}_initializeOnDelegatedTarget(t,e){return e||this.constructor.getOrCreateInstance(t.delegateTarget,this._getDelegateConfig())}_getOffset(){const{offset:t}=this._config;return"string"==typeof t?t.split(",").map((t=>Number.parseInt(t,10))):"function"==typeof t?e=>t(e,this._element):t}_resolvePossibleFunction(t){return"function"==typeof t?t.call(this._element):t}_getPopperConfig(t){const e={placement:t,modifiers:[{name:"flip",options:{fallbackPlacements:this._config.fallbackPlacements}},{name:"offset",options:{offset:this._getOffset()}},{name:"preventOverflow",options:{boundary:this._config.boundary}},{name:"arrow",options:{element:`.${this.constructor.NAME}-arrow`}},{name:"onChange",enabled:!0,phase:"afterWrite",fn:t=>this._handlePopperPlacementChange(t)}],onFirstUpdate:t=>{t.options.placement!==t.placement&&this._handlePopperPlacementChange(t)}};return{...e,..."function"==typeof this._config.popperConfig?this._config.popperConfig(e):this._config.popperConfig}}_addAttachmentClass(t){this.getTipElement().classList.add(`${this._getBasicClassPrefix()}-${this.updateAttachment(t)}`)}_getAttachment(t){return Ji[t.toUpperCase()]}_setListeners(){this._config.trigger.split(" ").forEach((t=>{if("click"===t)j.on(this._element,this.constructor.Event.CLICK,this._config.selector,(t=>this.toggle(t)));else if("manual"!==t){const e=t===hn?this.constructor.Event.MOUSEENTER:this.constructor.Event.FOCUSIN,i=t===hn?this.constructor.Event.MOUSELEAVE:this.constructor.Event.FOCUSOUT;j.on(this._element,e,this._config.selector,(t=>this._enter(t))),j.on(this._element,i,this._config.selector,(t=>this._leave(t)))}})),this._hideModalHandler=()=>{this._element&&this.hide()},j.on(this._element.closest(ln),cn,this._hideModalHandler),this._config.selector?this._config={...this._config,trigger:"manual",selector:""}:this._fixTitle()}_fixTitle(){const t=this._element.getAttribute("title"),e=typeof this._element.getAttribute("data-bs-original-title");(t||"string"!==e)&&(this._element.setAttribute("data-bs-original-title",t||""),!t||this._element.getAttribute("aria-label")||this._element.textContent||this._element.setAttribute("aria-label",t),this._element.setAttribute("title",""))}_enter(t,e){e=this._initializeOnDelegatedTarget(t,e),t&&(e._activeTrigger["focusin"===t.type?dn:hn]=!0),e.getTipElement().classList.contains(sn)||e._hoverState===on?e._hoverState=on:(clearTimeout(e._timeout),e._hoverState=on,e._config.delay&&e._config.delay.show?e._timeout=setTimeout((()=>{e._hoverState===on&&e.show()}),e._config.delay.show):e.show())}_leave(t,e){e=this._initializeOnDelegatedTarget(t,e),t&&(e._activeTrigger["focusout"===t.type?dn:hn]=e._element.contains(t.relatedTarget)),e._isWithActiveTrigger()||(clearTimeout(e._timeout),e._hoverState=rn,e._config.delay&&e._config.delay.hide?e._timeout=setTimeout((()=>{e._hoverState===rn&&e.hide()}),e._config.delay.hide):e.hide())}_isWithActiveTrigger(){for(const t in this._activeTrigger)if(this._activeTrigger[t])return!0;return!1}_getConfig(t){const e=U.getDataAttributes(this._element);return Object.keys(e).forEach((t=>{Gi.has(t)&&delete e[t]})),(t={...this.constructor.Default,...e,..."object"==typeof t&&t?t:{}}).container=!1===t.container?document.body:r(t.container),"number"==typeof t.delay&&(t.delay={show:t.delay,hide:t.delay}),"number"==typeof t.title&&(t.title=t.title.toString()),"number"==typeof t.content&&(t.content=t.content.toString()),a(Qi,t,this.constructor.DefaultType),t.sanitize&&(t.template=Yi(t.template,t.allowList,t.sanitizeFn)),t}_getDelegateConfig(){const t={};for(const e in this._config)this.constructor.Default[e]!==this._config[e]&&(t[e]=this._config[e]);return t}_cleanTipClass(){const t=this.getTipElement(),e=new RegExp(`(^|\\s)${this._getBasicClassPrefix()}\\S+`,"g"),i=t.getAttribute("class").match(e);null!==i&&i.length>0&&i.map((t=>t.trim())).forEach((e=>t.classList.remove(e)))}_getBasicClassPrefix(){return"bs-tooltip"}_handlePopperPlacementChange(t){const{state:e}=t;e&&(this.tip=e.elements.popper,this._cleanTipClass(),this._addAttachmentClass(this._getAttachment(e.placement)))}_disposePopper(){this._popper&&(this._popper.destroy(),this._popper=null)}static jQueryInterface(t){return this.each((function(){const e=un.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}g(un);const fn={...un.Default,placement:"right",offset:[0,8],trigger:"click",content:"",template:'<div class="popover" role="tooltip"><div class="popover-arrow"></div><h3 class="popover-header"></h3><div class="popover-body"></div></div>'},pn={...un.DefaultType,content:"(string|element|function)"},mn={HIDE:"hide.bs.popover",HIDDEN:"hidden.bs.popover",SHOW:"show.bs.popover",SHOWN:"shown.bs.popover",INSERTED:"inserted.bs.popover",CLICK:"click.bs.popover",FOCUSIN:"focusin.bs.popover",FOCUSOUT:"focusout.bs.popover",MOUSEENTER:"mouseenter.bs.popover",MOUSELEAVE:"mouseleave.bs.popover"};class gn extends un{static get Default(){return fn}static get NAME(){return"popover"}static get Event(){return mn}static get DefaultType(){return pn}isWithContent(){return this.getTitle()||this._getContent()}setContent(t){this._sanitizeAndSetContent(t,this.getTitle(),".popover-header"),this._sanitizeAndSetContent(t,this._getContent(),".popover-body")}_getContent(){return this._resolvePossibleFunction(this._config.content)}_getBasicClassPrefix(){return"bs-popover"}static jQueryInterface(t){return this.each((function(){const e=gn.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}g(gn);const _n="scrollspy",bn={offset:10,method:"auto",target:""},vn={offset:"number",method:"string",target:"(string|element)"},yn="active",wn=".nav-link, .list-group-item, .dropdown-item",En="position";class An extends B{constructor(t,e){super(t),this._scrollElement="BODY"===this._element.tagName?window:this._element,this._config=this._getConfig(e),this._offsets=[],this._targets=[],this._activeTarget=null,this._scrollHeight=0,j.on(this._scrollElement,"scroll.bs.scrollspy",(()=>this._process())),this.refresh(),this._process()}static get Default(){return bn}static get NAME(){return _n}refresh(){const t=this._scrollElement===this._scrollElement.window?"offset":En,e="auto"===this._config.method?t:this._config.method,n=e===En?this._getScrollTop():0;this._offsets=[],this._targets=[],this._scrollHeight=this._getScrollHeight(),V.find(wn,this._config.target).map((t=>{const s=i(t),o=s?V.findOne(s):null;if(o){const t=o.getBoundingClientRect();if(t.width||t.height)return[U[e](o).top+n,s]}return null})).filter((t=>t)).sort(((t,e)=>t[0]-e[0])).forEach((t=>{this._offsets.push(t[0]),this._targets.push(t[1])}))}dispose(){j.off(this._scrollElement,".bs.scrollspy"),super.dispose()}_getConfig(t){return(t={...bn,...U.getDataAttributes(this._element),..."object"==typeof t&&t?t:{}}).target=r(t.target)||document.documentElement,a(_n,t,vn),t}_getScrollTop(){return this._scrollElement===window?this._scrollElement.pageYOffset:this._scrollElement.scrollTop}_getScrollHeight(){return this._scrollElement.scrollHeight||Math.max(document.body.scrollHeight,document.documentElement.scrollHeight)}_getOffsetHeight(){return this._scrollElement===window?window.innerHeight:this._scrollElement.getBoundingClientRect().height}_process(){const t=this._getScrollTop()+this._config.offset,e=this._getScrollHeight(),i=this._config.offset+e-this._getOffsetHeight();if(this._scrollHeight!==e&&this.refresh(),t>=i){const t=this._targets[this._targets.length-1];this._activeTarget!==t&&this._activate(t)}else{if(this._activeTarget&&t<this._offsets[0]&&this._offsets[0]>0)return this._activeTarget=null,void this._clear();for(let e=this._offsets.length;e--;)this._activeTarget!==this._targets[e]&&t>=this._offsets[e]&&(void 0===this._offsets[e+1]||t<this._offsets[e+1])&&this._activate(this._targets[e])}}_activate(t){this._activeTarget=t,this._clear();const e=wn.split(",").map((e=>`${e}[data-bs-target="${t}"],${e}[href="${t}"]`)),i=V.findOne(e.join(","),this._config.target);i.classList.add(yn),i.classList.contains("dropdown-item")?V.findOne(".dropdown-toggle",i.closest(".dropdown")).classList.add(yn):V.parents(i,".nav, .list-group").forEach((t=>{V.prev(t,".nav-link, .list-group-item").forEach((t=>t.classList.add(yn))),V.prev(t,".nav-item").forEach((t=>{V.children(t,".nav-link").forEach((t=>t.classList.add(yn)))}))})),j.trigger(this._scrollElement,"activate.bs.scrollspy",{relatedTarget:t})}_clear(){V.find(wn,this._config.target).filter((t=>t.classList.contains(yn))).forEach((t=>t.classList.remove(yn)))}static jQueryInterface(t){return this.each((function(){const e=An.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}j.on(window,"load.bs.scrollspy.data-api",(()=>{V.find('[data-bs-spy="scroll"]').forEach((t=>new An(t)))})),g(An);const Tn="active",On="fade",Cn="show",kn=".active",Ln=":scope > li > .active";class xn extends B{static get NAME(){return"tab"}show(){if(this._element.parentNode&&this._element.parentNode.nodeType===Node.ELEMENT_NODE&&this._element.classList.contains(Tn))return;let t;const e=n(this._element),i=this._element.closest(".nav, .list-group");if(i){const e="UL"===i.nodeName||"OL"===i.nodeName?Ln:kn;t=V.find(e,i),t=t[t.length-1]}const s=t?j.trigger(t,"hide.bs.tab",{relatedTarget:this._element}):null;if(j.trigger(this._element,"show.bs.tab",{relatedTarget:t}).defaultPrevented||null!==s&&s.defaultPrevented)return;this._activate(this._element,i);const o=()=>{j.trigger(t,"hidden.bs.tab",{relatedTarget:this._element}),j.trigger(this._element,"shown.bs.tab",{relatedTarget:t})};e?this._activate(e,e.parentNode,o):o()}_activate(t,e,i){const n=(!e||"UL"!==e.nodeName&&"OL"!==e.nodeName?V.children(e,kn):V.find(Ln,e))[0],s=i&&n&&n.classList.contains(On),o=()=>this._transitionComplete(t,n,i);n&&s?(n.classList.remove(Cn),this._queueCallback(o,t,!0)):o()}_transitionComplete(t,e,i){if(e){e.classList.remove(Tn);const t=V.findOne(":scope > .dropdown-menu .active",e.parentNode);t&&t.classList.remove(Tn),"tab"===e.getAttribute("role")&&e.setAttribute("aria-selected",!1)}t.classList.add(Tn),"tab"===t.getAttribute("role")&&t.setAttribute("aria-selected",!0),u(t),t.classList.contains(On)&&t.classList.add(Cn);let n=t.parentNode;if(n&&"LI"===n.nodeName&&(n=n.parentNode),n&&n.classList.contains("dropdown-menu")){const e=t.closest(".dropdown");e&&V.find(".dropdown-toggle",e).forEach((t=>t.classList.add(Tn))),t.setAttribute("aria-expanded",!0)}i&&i()}static jQueryInterface(t){return this.each((function(){const e=xn.getOrCreateInstance(this);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t]()}}))}}j.on(document,"click.bs.tab.data-api",'[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]',(function(t){["A","AREA"].includes(this.tagName)&&t.preventDefault(),c(this)||xn.getOrCreateInstance(this).show()})),g(xn);const Dn="toast",Sn="hide",Nn="show",In="showing",Pn={animation:"boolean",autohide:"boolean",delay:"number"},jn={animation:!0,autohide:!0,delay:5e3};class Mn extends B{constructor(t,e){super(t),this._config=this._getConfig(e),this._timeout=null,this._hasMouseInteraction=!1,this._hasKeyboardInteraction=!1,this._setListeners()}static get DefaultType(){return Pn}static get Default(){return jn}static get NAME(){return Dn}show(){j.trigger(this._element,"show.bs.toast").defaultPrevented||(this._clearTimeout(),this._config.animation&&this._element.classList.add("fade"),this._element.classList.remove(Sn),u(this._element),this._element.classList.add(Nn),this._element.classList.add(In),this._queueCallback((()=>{this._element.classList.remove(In),j.trigger(this._element,"shown.bs.toast"),this._maybeScheduleHide()}),this._element,this._config.animation))}hide(){this._element.classList.contains(Nn)&&(j.trigger(this._element,"hide.bs.toast").defaultPrevented||(this._element.classList.add(In),this._queueCallback((()=>{this._element.classList.add(Sn),this._element.classList.remove(In),this._element.classList.remove(Nn),j.trigger(this._element,"hidden.bs.toast")}),this._element,this._config.animation)))}dispose(){this._clearTimeout(),this._element.classList.contains(Nn)&&this._element.classList.remove(Nn),super.dispose()}_getConfig(t){return t={...jn,...U.getDataAttributes(this._element),..."object"==typeof t&&t?t:{}},a(Dn,t,this.constructor.DefaultType),t}_maybeScheduleHide(){this._config.autohide&&(this._hasMouseInteraction||this._hasKeyboardInteraction||(this._timeout=setTimeout((()=>{this.hide()}),this._config.delay)))}_onInteraction(t,e){switch(t.type){case"mouseover":case"mouseout":this._hasMouseInteraction=e;break;case"focusin":case"focusout":this._hasKeyboardInteraction=e}if(e)return void this._clearTimeout();const i=t.relatedTarget;this._element===i||this._element.contains(i)||this._maybeScheduleHide()}_setListeners(){j.on(this._element,"mouseover.bs.toast",(t=>this._onInteraction(t,!0))),j.on(this._element,"mouseout.bs.toast",(t=>this._onInteraction(t,!1))),j.on(this._element,"focusin.bs.toast",(t=>this._onInteraction(t,!0))),j.on(this._element,"focusout.bs.toast",(t=>this._onInteraction(t,!1)))}_clearTimeout(){clearTimeout(this._timeout),this._timeout=null}static jQueryInterface(t){return this.each((function(){const e=Mn.getOrCreateInstance(this,t);if("string"==typeof t){if(void 0===e[t])throw new TypeError(`No method named "${t}"`);e[t](this)}}))}}return R(Mn),g(Mn),{Alert:W,Button:z,Carousel:st,Collapse:pt,Dropdown:hi,Modal:Hi,Offcanvas:Fi,Popover:gn,ScrollSpy:An,Tab:xn,Toast:Mn,Tooltip:un}})); +//# sourceMappingURL=bootstrap.bundle.min.js.map \ No newline at end of file diff --git a/site_libs/clipboard/clipboard.min.js b/site_libs/clipboard/clipboard.min.js new file mode 100644 index 00000000..1103f811 --- /dev/null +++ b/site_libs/clipboard/clipboard.min.js @@ -0,0 +1,7 @@ +/*! + * clipboard.js v2.0.11 + * https://clipboardjs.com/ + * + * Licensed MIT Ā© Zeno Rocha + */ +!function(t,e){"object"==typeof exports&&"object"==typeof module?module.exports=e():"function"==typeof define&&define.amd?define([],e):"object"==typeof exports?exports.ClipboardJS=e():t.ClipboardJS=e()}(this,function(){return n={686:function(t,e,n){"use strict";n.d(e,{default:function(){return b}});var e=n(279),i=n.n(e),e=n(370),u=n.n(e),e=n(817),r=n.n(e);function c(t){try{return document.execCommand(t)}catch(t){return}}var a=function(t){t=r()(t);return c("cut"),t};function o(t,e){var n,o,t=(n=t,o="rtl"===document.documentElement.getAttribute("dir"),(t=document.createElement("textarea")).style.fontSize="12pt",t.style.border="0",t.style.padding="0",t.style.margin="0",t.style.position="absolute",t.style[o?"right":"left"]="-9999px",o=window.pageYOffset||document.documentElement.scrollTop,t.style.top="".concat(o,"px"),t.setAttribute("readonly",""),t.value=n,t);return e.container.appendChild(t),e=r()(t),c("copy"),t.remove(),e}var f=function(t){var e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{container:document.body},n="";return"string"==typeof t?n=o(t,e):t instanceof HTMLInputElement&&!["text","search","url","tel","password"].includes(null==t?void 0:t.type)?n=o(t.value,e):(n=r()(t),c("copy")),n};function l(t){return(l="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}var s=function(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:{},e=t.action,n=void 0===e?"copy":e,o=t.container,e=t.target,t=t.text;if("copy"!==n&&"cut"!==n)throw new Error('Invalid "action" value, use either "copy" or "cut"');if(void 0!==e){if(!e||"object"!==l(e)||1!==e.nodeType)throw new Error('Invalid "target" value, use a valid Element');if("copy"===n&&e.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if("cut"===n&&(e.hasAttribute("readonly")||e.hasAttribute("disabled")))throw new Error('Invalid "target" attribute. You can\'t cut text from elements with "readonly" or "disabled" attributes')}return t?f(t,{container:o}):e?"cut"===n?a(e):f(e,{container:o}):void 0};function p(t){return(p="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(t){return typeof t}:function(t){return t&&"function"==typeof Symbol&&t.constructor===Symbol&&t!==Symbol.prototype?"symbol":typeof t})(t)}function d(t,e){for(var n=0;n<e.length;n++){var o=e[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(t,o.key,o)}}function y(t,e){return(y=Object.setPrototypeOf||function(t,e){return t.__proto__=e,t})(t,e)}function h(n){var o=function(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Date.prototype.toString.call(Reflect.construct(Date,[],function(){})),!0}catch(t){return!1}}();return function(){var t,e=v(n);return t=o?(t=v(this).constructor,Reflect.construct(e,arguments,t)):e.apply(this,arguments),e=this,!(t=t)||"object"!==p(t)&&"function"!=typeof t?function(t){if(void 0!==t)return t;throw new ReferenceError("this hasn't been initialised - super() hasn't been called")}(e):t}}function v(t){return(v=Object.setPrototypeOf?Object.getPrototypeOf:function(t){return t.__proto__||Object.getPrototypeOf(t)})(t)}function m(t,e){t="data-clipboard-".concat(t);if(e.hasAttribute(t))return e.getAttribute(t)}var b=function(){!function(t,e){if("function"!=typeof e&&null!==e)throw new TypeError("Super expression must either be null or a function");t.prototype=Object.create(e&&e.prototype,{constructor:{value:t,writable:!0,configurable:!0}}),e&&y(t,e)}(r,i());var t,e,n,o=h(r);function r(t,e){var n;return function(t){if(!(t instanceof r))throw new TypeError("Cannot call a class as a function")}(this),(n=o.call(this)).resolveOptions(e),n.listenClick(t),n}return t=r,n=[{key:"copy",value:function(t){var e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:{container:document.body};return f(t,e)}},{key:"cut",value:function(t){return a(t)}},{key:"isSupported",value:function(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:["copy","cut"],t="string"==typeof t?[t]:t,e=!!document.queryCommandSupported;return t.forEach(function(t){e=e&&!!document.queryCommandSupported(t)}),e}}],(e=[{key:"resolveOptions",value:function(){var t=0<arguments.length&&void 0!==arguments[0]?arguments[0]:{};this.action="function"==typeof t.action?t.action:this.defaultAction,this.target="function"==typeof t.target?t.target:this.defaultTarget,this.text="function"==typeof t.text?t.text:this.defaultText,this.container="object"===p(t.container)?t.container:document.body}},{key:"listenClick",value:function(t){var e=this;this.listener=u()(t,"click",function(t){return e.onClick(t)})}},{key:"onClick",value:function(t){var e=t.delegateTarget||t.currentTarget,n=this.action(e)||"copy",t=s({action:n,container:this.container,target:this.target(e),text:this.text(e)});this.emit(t?"success":"error",{action:n,text:t,trigger:e,clearSelection:function(){e&&e.focus(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(t){return m("action",t)}},{key:"defaultTarget",value:function(t){t=m("target",t);if(t)return document.querySelector(t)}},{key:"defaultText",value:function(t){return m("text",t)}},{key:"destroy",value:function(){this.listener.destroy()}}])&&d(t.prototype,e),n&&d(t,n),r}()},828:function(t){var e;"undefined"==typeof Element||Element.prototype.matches||((e=Element.prototype).matches=e.matchesSelector||e.mozMatchesSelector||e.msMatchesSelector||e.oMatchesSelector||e.webkitMatchesSelector),t.exports=function(t,e){for(;t&&9!==t.nodeType;){if("function"==typeof t.matches&&t.matches(e))return t;t=t.parentNode}}},438:function(t,e,n){var u=n(828);function i(t,e,n,o,r){var i=function(e,n,t,o){return function(t){t.delegateTarget=u(t.target,n),t.delegateTarget&&o.call(e,t)}}.apply(this,arguments);return t.addEventListener(n,i,r),{destroy:function(){t.removeEventListener(n,i,r)}}}t.exports=function(t,e,n,o,r){return"function"==typeof t.addEventListener?i.apply(null,arguments):"function"==typeof n?i.bind(null,document).apply(null,arguments):("string"==typeof t&&(t=document.querySelectorAll(t)),Array.prototype.map.call(t,function(t){return i(t,e,n,o,r)}))}},879:function(t,n){n.node=function(t){return void 0!==t&&t instanceof HTMLElement&&1===t.nodeType},n.nodeList=function(t){var e=Object.prototype.toString.call(t);return void 0!==t&&("[object NodeList]"===e||"[object HTMLCollection]"===e)&&"length"in t&&(0===t.length||n.node(t[0]))},n.string=function(t){return"string"==typeof t||t instanceof String},n.fn=function(t){return"[object Function]"===Object.prototype.toString.call(t)}},370:function(t,e,n){var f=n(879),l=n(438);t.exports=function(t,e,n){if(!t&&!e&&!n)throw new Error("Missing required arguments");if(!f.string(e))throw new TypeError("Second argument must be a String");if(!f.fn(n))throw new TypeError("Third argument must be a Function");if(f.node(t))return c=e,a=n,(u=t).addEventListener(c,a),{destroy:function(){u.removeEventListener(c,a)}};if(f.nodeList(t))return o=t,r=e,i=n,Array.prototype.forEach.call(o,function(t){t.addEventListener(r,i)}),{destroy:function(){Array.prototype.forEach.call(o,function(t){t.removeEventListener(r,i)})}};if(f.string(t))return t=t,e=e,n=n,l(document.body,t,e,n);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList");var o,r,i,u,c,a}},817:function(t){t.exports=function(t){var e,n="SELECT"===t.nodeName?(t.focus(),t.value):"INPUT"===t.nodeName||"TEXTAREA"===t.nodeName?((e=t.hasAttribute("readonly"))||t.setAttribute("readonly",""),t.select(),t.setSelectionRange(0,t.value.length),e||t.removeAttribute("readonly"),t.value):(t.hasAttribute("contenteditable")&&t.focus(),n=window.getSelection(),(e=document.createRange()).selectNodeContents(t),n.removeAllRanges(),n.addRange(e),n.toString());return n}},279:function(t){function e(){}e.prototype={on:function(t,e,n){var o=this.e||(this.e={});return(o[t]||(o[t]=[])).push({fn:e,ctx:n}),this},once:function(t,e,n){var o=this;function r(){o.off(t,r),e.apply(n,arguments)}return r._=e,this.on(t,r,n)},emit:function(t){for(var e=[].slice.call(arguments,1),n=((this.e||(this.e={}))[t]||[]).slice(),o=0,r=n.length;o<r;o++)n[o].fn.apply(n[o].ctx,e);return this},off:function(t,e){var n=this.e||(this.e={}),o=n[t],r=[];if(o&&e)for(var i=0,u=o.length;i<u;i++)o[i].fn!==e&&o[i].fn._!==e&&r.push(o[i]);return r.length?n[t]=r:delete n[t],this}},t.exports=e,t.exports.TinyEmitter=e}},r={},o.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return o.d(e,{a:e}),e},o.d=function(t,e){for(var n in e)o.o(e,n)&&!o.o(t,n)&&Object.defineProperty(t,n,{enumerable:!0,get:e[n]})},o.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},o(686).default;function o(t){if(r[t])return r[t].exports;var e=r[t]={exports:{}};return n[t](e,e.exports,o),e.exports}var n,r}); \ No newline at end of file diff --git a/site_libs/quarto-html/anchor.min.js b/site_libs/quarto-html/anchor.min.js new file mode 100644 index 00000000..1c2b86fa --- /dev/null +++ b/site_libs/quarto-html/anchor.min.js @@ -0,0 +1,9 @@ +// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt Expat +// +// AnchorJS - v4.3.1 - 2021-04-17 +// https://www.bryanbraun.com/anchorjs/ +// Copyright (c) 2021 Bryan Braun; Licensed MIT +// +// @license magnet:?xt=urn:btih:d3d9a9a6595521f9666a5e94cc830dab83b65699&dn=expat.txt Expat +!function(A,e){"use strict";"function"==typeof define&&define.amd?define([],e):"object"==typeof module&&module.exports?module.exports=e():(A.AnchorJS=e(),A.anchors=new A.AnchorJS)}(this,function(){"use strict";return function(A){function d(A){A.icon=Object.prototype.hasOwnProperty.call(A,"icon")?A.icon:"ī§",A.visible=Object.prototype.hasOwnProperty.call(A,"visible")?A.visible:"hover",A.placement=Object.prototype.hasOwnProperty.call(A,"placement")?A.placement:"right",A.ariaLabel=Object.prototype.hasOwnProperty.call(A,"ariaLabel")?A.ariaLabel:"Anchor",A.class=Object.prototype.hasOwnProperty.call(A,"class")?A.class:"",A.base=Object.prototype.hasOwnProperty.call(A,"base")?A.base:"",A.truncate=Object.prototype.hasOwnProperty.call(A,"truncate")?Math.floor(A.truncate):64,A.titleText=Object.prototype.hasOwnProperty.call(A,"titleText")?A.titleText:""}function w(A){var e;if("string"==typeof A||A instanceof String)e=[].slice.call(document.querySelectorAll(A));else{if(!(Array.isArray(A)||A instanceof NodeList))throw new TypeError("The selector provided to AnchorJS was invalid.");e=[].slice.call(A)}return e}this.options=A||{},this.elements=[],d(this.options),this.isTouchDevice=function(){return Boolean("ontouchstart"in window||window.TouchEvent||window.DocumentTouch&&document instanceof DocumentTouch)},this.add=function(A){var e,t,o,i,n,s,a,c,r,l,h,u,p=[];if(d(this.options),"touch"===(l=this.options.visible)&&(l=this.isTouchDevice()?"always":"hover"),0===(e=w(A=A||"h2, h3, h4, h5, h6")).length)return this;for(null===document.head.querySelector("style.anchorjs")&&((u=document.createElement("style")).className="anchorjs",u.appendChild(document.createTextNode("")),void 0===(A=document.head.querySelector('[rel="stylesheet"],style'))?document.head.appendChild(u):document.head.insertBefore(u,A),u.sheet.insertRule(".anchorjs-link{opacity:0;text-decoration:none;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}",u.sheet.cssRules.length),u.sheet.insertRule(":hover>.anchorjs-link,.anchorjs-link:focus{opacity:1}",u.sheet.cssRules.length),u.sheet.insertRule("[data-anchorjs-icon]::after{content:attr(data-anchorjs-icon)}",u.sheet.cssRules.length),u.sheet.insertRule('@font-face{font-family:anchorjs-icons;src:url(data:n/a;base64,AAEAAAALAIAAAwAwT1MvMg8yG2cAAAE4AAAAYGNtYXDp3gC3AAABpAAAAExnYXNwAAAAEAAAA9wAAAAIZ2x5ZlQCcfwAAAH4AAABCGhlYWQHFvHyAAAAvAAAADZoaGVhBnACFwAAAPQAAAAkaG10eASAADEAAAGYAAAADGxvY2EACACEAAAB8AAAAAhtYXhwAAYAVwAAARgAAAAgbmFtZQGOH9cAAAMAAAAAunBvc3QAAwAAAAADvAAAACAAAQAAAAEAAHzE2p9fDzz1AAkEAAAAAADRecUWAAAAANQA6R8AAAAAAoACwAAAAAgAAgAAAAAAAAABAAADwP/AAAACgAAA/9MCrQABAAAAAAAAAAAAAAAAAAAAAwABAAAAAwBVAAIAAAAAAAIAAAAAAAAAAAAAAAAAAAAAAAMCQAGQAAUAAAKZAswAAACPApkCzAAAAesAMwEJAAAAAAAAAAAAAAAAAAAAARAAAAAAAAAAAAAAAAAAAAAAQAAg//0DwP/AAEADwABAAAAAAQAAAAAAAAAAAAAAIAAAAAAAAAIAAAACgAAxAAAAAwAAAAMAAAAcAAEAAwAAABwAAwABAAAAHAAEADAAAAAIAAgAAgAAACDpy//9//8AAAAg6cv//f///+EWNwADAAEAAAAAAAAAAAAAAAAACACEAAEAAAAAAAAAAAAAAAAxAAACAAQARAKAAsAAKwBUAAABIiYnJjQ3NzY2MzIWFxYUBwcGIicmNDc3NjQnJiYjIgYHBwYUFxYUBwYGIwciJicmNDc3NjIXFhQHBwYUFxYWMzI2Nzc2NCcmNDc2MhcWFAcHBgYjARQGDAUtLXoWOR8fORYtLTgKGwoKCjgaGg0gEhIgDXoaGgkJBQwHdR85Fi0tOAobCgoKOBoaDSASEiANehoaCQkKGwotLXoWOR8BMwUFLYEuehYXFxYugC44CQkKGwo4GkoaDQ0NDXoaShoKGwoFBe8XFi6ALjgJCQobCjgaShoNDQ0NehpKGgobCgoKLYEuehYXAAAADACWAAEAAAAAAAEACAAAAAEAAAAAAAIAAwAIAAEAAAAAAAMACAAAAAEAAAAAAAQACAAAAAEAAAAAAAUAAQALAAEAAAAAAAYACAAAAAMAAQQJAAEAEAAMAAMAAQQJAAIABgAcAAMAAQQJAAMAEAAMAAMAAQQJAAQAEAAMAAMAAQQJAAUAAgAiAAMAAQQJAAYAEAAMYW5jaG9yanM0MDBAAGEAbgBjAGgAbwByAGoAcwA0ADAAMABAAAAAAwAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAAH//wAP) format("truetype")}',u.sheet.cssRules.length)),u=document.querySelectorAll("[id]"),t=[].map.call(u,function(A){return A.id}),i=0;i<e.length;i++)if(this.hasAnchorJSLink(e[i]))p.push(i);else{if(e[i].hasAttribute("id"))o=e[i].getAttribute("id");else if(e[i].hasAttribute("data-anchor-id"))o=e[i].getAttribute("data-anchor-id");else{for(c=a=this.urlify(e[i].textContent),s=0;n=t.indexOf(c=void 0!==n?a+"-"+s:c),s+=1,-1!==n;);n=void 0,t.push(c),e[i].setAttribute("id",c),o=c}(r=document.createElement("a")).className="anchorjs-link "+this.options.class,r.setAttribute("aria-label",this.options.ariaLabel),r.setAttribute("data-anchorjs-icon",this.options.icon),this.options.titleText&&(r.title=this.options.titleText),h=document.querySelector("base")?window.location.pathname+window.location.search:"",h=this.options.base||h,r.href=h+"#"+o,"always"===l&&(r.style.opacity="1"),"ī§"===this.options.icon&&(r.style.font="1em/1 anchorjs-icons","left"===this.options.placement&&(r.style.lineHeight="inherit")),"left"===this.options.placement?(r.style.position="absolute",r.style.marginLeft="-1em",r.style.paddingRight=".5em",e[i].insertBefore(r,e[i].firstChild)):(r.style.paddingLeft=".375em",e[i].appendChild(r))}for(i=0;i<p.length;i++)e.splice(p[i]-i,1);return this.elements=this.elements.concat(e),this},this.remove=function(A){for(var e,t,o=w(A),i=0;i<o.length;i++)(t=o[i].querySelector(".anchorjs-link"))&&(-1!==(e=this.elements.indexOf(o[i]))&&this.elements.splice(e,1),o[i].removeChild(t));return this},this.removeAll=function(){this.remove(this.elements)},this.urlify=function(A){var e=document.createElement("textarea");return e.innerHTML=A,A=e.value,this.options.truncate||d(this.options),A.trim().replace(/'/gi,"").replace(/[& +$,:;=?@"#{}|^~[`%!'<>\]./()*\\\n\t\b\v\u00A0]/g,"-").replace(/-{2,}/g,"-").substring(0,this.options.truncate).replace(/^-+|-+$/gm,"").toLowerCase()},this.hasAnchorJSLink=function(A){var e=A.firstChild&&-1<(" "+A.firstChild.className+" ").indexOf(" anchorjs-link "),A=A.lastChild&&-1<(" "+A.lastChild.className+" ").indexOf(" anchorjs-link ");return e||A||!1}}}); +// @license-end \ No newline at end of file diff --git a/site_libs/quarto-html/popper.min.js b/site_libs/quarto-html/popper.min.js new file mode 100644 index 00000000..2269d669 --- /dev/null +++ b/site_libs/quarto-html/popper.min.js @@ -0,0 +1,6 @@ +/** + * @popperjs/core v2.11.4 - MIT License + */ + +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).Popper={})}(this,(function(e){"use strict";function t(e){if(null==e)return window;if("[object Window]"!==e.toString()){var t=e.ownerDocument;return t&&t.defaultView||window}return e}function n(e){return e instanceof t(e).Element||e instanceof Element}function r(e){return e instanceof t(e).HTMLElement||e instanceof HTMLElement}function o(e){return"undefined"!=typeof ShadowRoot&&(e instanceof t(e).ShadowRoot||e instanceof ShadowRoot)}var i=Math.max,a=Math.min,s=Math.round;function f(e,t){void 0===t&&(t=!1);var n=e.getBoundingClientRect(),o=1,i=1;if(r(e)&&t){var a=e.offsetHeight,f=e.offsetWidth;f>0&&(o=s(n.width)/f||1),a>0&&(i=s(n.height)/a||1)}return{width:n.width/o,height:n.height/i,top:n.top/i,right:n.right/o,bottom:n.bottom/i,left:n.left/o,x:n.left/o,y:n.top/i}}function c(e){var n=t(e);return{scrollLeft:n.pageXOffset,scrollTop:n.pageYOffset}}function p(e){return e?(e.nodeName||"").toLowerCase():null}function u(e){return((n(e)?e.ownerDocument:e.document)||window.document).documentElement}function l(e){return f(u(e)).left+c(e).scrollLeft}function d(e){return t(e).getComputedStyle(e)}function h(e){var t=d(e),n=t.overflow,r=t.overflowX,o=t.overflowY;return/auto|scroll|overlay|hidden/.test(n+o+r)}function m(e,n,o){void 0===o&&(o=!1);var i,a,d=r(n),m=r(n)&&function(e){var t=e.getBoundingClientRect(),n=s(t.width)/e.offsetWidth||1,r=s(t.height)/e.offsetHeight||1;return 1!==n||1!==r}(n),v=u(n),g=f(e,m),y={scrollLeft:0,scrollTop:0},b={x:0,y:0};return(d||!d&&!o)&&(("body"!==p(n)||h(v))&&(y=(i=n)!==t(i)&&r(i)?{scrollLeft:(a=i).scrollLeft,scrollTop:a.scrollTop}:c(i)),r(n)?((b=f(n,!0)).x+=n.clientLeft,b.y+=n.clientTop):v&&(b.x=l(v))),{x:g.left+y.scrollLeft-b.x,y:g.top+y.scrollTop-b.y,width:g.width,height:g.height}}function v(e){var t=f(e),n=e.offsetWidth,r=e.offsetHeight;return Math.abs(t.width-n)<=1&&(n=t.width),Math.abs(t.height-r)<=1&&(r=t.height),{x:e.offsetLeft,y:e.offsetTop,width:n,height:r}}function g(e){return"html"===p(e)?e:e.assignedSlot||e.parentNode||(o(e)?e.host:null)||u(e)}function y(e){return["html","body","#document"].indexOf(p(e))>=0?e.ownerDocument.body:r(e)&&h(e)?e:y(g(e))}function b(e,n){var r;void 0===n&&(n=[]);var o=y(e),i=o===(null==(r=e.ownerDocument)?void 0:r.body),a=t(o),s=i?[a].concat(a.visualViewport||[],h(o)?o:[]):o,f=n.concat(s);return i?f:f.concat(b(g(s)))}function x(e){return["table","td","th"].indexOf(p(e))>=0}function w(e){return r(e)&&"fixed"!==d(e).position?e.offsetParent:null}function O(e){for(var n=t(e),i=w(e);i&&x(i)&&"static"===d(i).position;)i=w(i);return i&&("html"===p(i)||"body"===p(i)&&"static"===d(i).position)?n:i||function(e){var t=-1!==navigator.userAgent.toLowerCase().indexOf("firefox");if(-1!==navigator.userAgent.indexOf("Trident")&&r(e)&&"fixed"===d(e).position)return null;var n=g(e);for(o(n)&&(n=n.host);r(n)&&["html","body"].indexOf(p(n))<0;){var i=d(n);if("none"!==i.transform||"none"!==i.perspective||"paint"===i.contain||-1!==["transform","perspective"].indexOf(i.willChange)||t&&"filter"===i.willChange||t&&i.filter&&"none"!==i.filter)return n;n=n.parentNode}return null}(e)||n}var j="top",E="bottom",D="right",A="left",L="auto",P=[j,E,D,A],M="start",k="end",W="viewport",B="popper",H=P.reduce((function(e,t){return e.concat([t+"-"+M,t+"-"+k])}),[]),T=[].concat(P,[L]).reduce((function(e,t){return e.concat([t,t+"-"+M,t+"-"+k])}),[]),R=["beforeRead","read","afterRead","beforeMain","main","afterMain","beforeWrite","write","afterWrite"];function S(e){var t=new Map,n=new Set,r=[];function o(e){n.add(e.name),[].concat(e.requires||[],e.requiresIfExists||[]).forEach((function(e){if(!n.has(e)){var r=t.get(e);r&&o(r)}})),r.push(e)}return e.forEach((function(e){t.set(e.name,e)})),e.forEach((function(e){n.has(e.name)||o(e)})),r}function C(e){return e.split("-")[0]}function q(e,t){var n=t.getRootNode&&t.getRootNode();if(e.contains(t))return!0;if(n&&o(n)){var r=t;do{if(r&&e.isSameNode(r))return!0;r=r.parentNode||r.host}while(r)}return!1}function V(e){return Object.assign({},e,{left:e.x,top:e.y,right:e.x+e.width,bottom:e.y+e.height})}function N(e,r){return r===W?V(function(e){var n=t(e),r=u(e),o=n.visualViewport,i=r.clientWidth,a=r.clientHeight,s=0,f=0;return o&&(i=o.width,a=o.height,/^((?!chrome|android).)*safari/i.test(navigator.userAgent)||(s=o.offsetLeft,f=o.offsetTop)),{width:i,height:a,x:s+l(e),y:f}}(e)):n(r)?function(e){var t=f(e);return t.top=t.top+e.clientTop,t.left=t.left+e.clientLeft,t.bottom=t.top+e.clientHeight,t.right=t.left+e.clientWidth,t.width=e.clientWidth,t.height=e.clientHeight,t.x=t.left,t.y=t.top,t}(r):V(function(e){var t,n=u(e),r=c(e),o=null==(t=e.ownerDocument)?void 0:t.body,a=i(n.scrollWidth,n.clientWidth,o?o.scrollWidth:0,o?o.clientWidth:0),s=i(n.scrollHeight,n.clientHeight,o?o.scrollHeight:0,o?o.clientHeight:0),f=-r.scrollLeft+l(e),p=-r.scrollTop;return"rtl"===d(o||n).direction&&(f+=i(n.clientWidth,o?o.clientWidth:0)-a),{width:a,height:s,x:f,y:p}}(u(e)))}function I(e,t,o){var s="clippingParents"===t?function(e){var t=b(g(e)),o=["absolute","fixed"].indexOf(d(e).position)>=0&&r(e)?O(e):e;return n(o)?t.filter((function(e){return n(e)&&q(e,o)&&"body"!==p(e)})):[]}(e):[].concat(t),f=[].concat(s,[o]),c=f[0],u=f.reduce((function(t,n){var r=N(e,n);return t.top=i(r.top,t.top),t.right=a(r.right,t.right),t.bottom=a(r.bottom,t.bottom),t.left=i(r.left,t.left),t}),N(e,c));return u.width=u.right-u.left,u.height=u.bottom-u.top,u.x=u.left,u.y=u.top,u}function _(e){return e.split("-")[1]}function F(e){return["top","bottom"].indexOf(e)>=0?"x":"y"}function U(e){var t,n=e.reference,r=e.element,o=e.placement,i=o?C(o):null,a=o?_(o):null,s=n.x+n.width/2-r.width/2,f=n.y+n.height/2-r.height/2;switch(i){case j:t={x:s,y:n.y-r.height};break;case E:t={x:s,y:n.y+n.height};break;case D:t={x:n.x+n.width,y:f};break;case A:t={x:n.x-r.width,y:f};break;default:t={x:n.x,y:n.y}}var c=i?F(i):null;if(null!=c){var p="y"===c?"height":"width";switch(a){case M:t[c]=t[c]-(n[p]/2-r[p]/2);break;case k:t[c]=t[c]+(n[p]/2-r[p]/2)}}return t}function z(e){return Object.assign({},{top:0,right:0,bottom:0,left:0},e)}function X(e,t){return t.reduce((function(t,n){return t[n]=e,t}),{})}function Y(e,t){void 0===t&&(t={});var r=t,o=r.placement,i=void 0===o?e.placement:o,a=r.boundary,s=void 0===a?"clippingParents":a,c=r.rootBoundary,p=void 0===c?W:c,l=r.elementContext,d=void 0===l?B:l,h=r.altBoundary,m=void 0!==h&&h,v=r.padding,g=void 0===v?0:v,y=z("number"!=typeof g?g:X(g,P)),b=d===B?"reference":B,x=e.rects.popper,w=e.elements[m?b:d],O=I(n(w)?w:w.contextElement||u(e.elements.popper),s,p),A=f(e.elements.reference),L=U({reference:A,element:x,strategy:"absolute",placement:i}),M=V(Object.assign({},x,L)),k=d===B?M:A,H={top:O.top-k.top+y.top,bottom:k.bottom-O.bottom+y.bottom,left:O.left-k.left+y.left,right:k.right-O.right+y.right},T=e.modifiersData.offset;if(d===B&&T){var R=T[i];Object.keys(H).forEach((function(e){var t=[D,E].indexOf(e)>=0?1:-1,n=[j,E].indexOf(e)>=0?"y":"x";H[e]+=R[n]*t}))}return H}var G={placement:"bottom",modifiers:[],strategy:"absolute"};function J(){for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];return!t.some((function(e){return!(e&&"function"==typeof e.getBoundingClientRect)}))}function K(e){void 0===e&&(e={});var t=e,r=t.defaultModifiers,o=void 0===r?[]:r,i=t.defaultOptions,a=void 0===i?G:i;return function(e,t,r){void 0===r&&(r=a);var i,s,f={placement:"bottom",orderedModifiers:[],options:Object.assign({},G,a),modifiersData:{},elements:{reference:e,popper:t},attributes:{},styles:{}},c=[],p=!1,u={state:f,setOptions:function(r){var i="function"==typeof r?r(f.options):r;l(),f.options=Object.assign({},a,f.options,i),f.scrollParents={reference:n(e)?b(e):e.contextElement?b(e.contextElement):[],popper:b(t)};var s,p,d=function(e){var t=S(e);return R.reduce((function(e,n){return e.concat(t.filter((function(e){return e.phase===n})))}),[])}((s=[].concat(o,f.options.modifiers),p=s.reduce((function(e,t){var n=e[t.name];return e[t.name]=n?Object.assign({},n,t,{options:Object.assign({},n.options,t.options),data:Object.assign({},n.data,t.data)}):t,e}),{}),Object.keys(p).map((function(e){return p[e]}))));return f.orderedModifiers=d.filter((function(e){return e.enabled})),f.orderedModifiers.forEach((function(e){var t=e.name,n=e.options,r=void 0===n?{}:n,o=e.effect;if("function"==typeof o){var i=o({state:f,name:t,instance:u,options:r}),a=function(){};c.push(i||a)}})),u.update()},forceUpdate:function(){if(!p){var e=f.elements,t=e.reference,n=e.popper;if(J(t,n)){f.rects={reference:m(t,O(n),"fixed"===f.options.strategy),popper:v(n)},f.reset=!1,f.placement=f.options.placement,f.orderedModifiers.forEach((function(e){return f.modifiersData[e.name]=Object.assign({},e.data)}));for(var r=0;r<f.orderedModifiers.length;r++)if(!0!==f.reset){var o=f.orderedModifiers[r],i=o.fn,a=o.options,s=void 0===a?{}:a,c=o.name;"function"==typeof i&&(f=i({state:f,options:s,name:c,instance:u})||f)}else f.reset=!1,r=-1}}},update:(i=function(){return new Promise((function(e){u.forceUpdate(),e(f)}))},function(){return s||(s=new Promise((function(e){Promise.resolve().then((function(){s=void 0,e(i())}))}))),s}),destroy:function(){l(),p=!0}};if(!J(e,t))return u;function l(){c.forEach((function(e){return e()})),c=[]}return u.setOptions(r).then((function(e){!p&&r.onFirstUpdate&&r.onFirstUpdate(e)})),u}}var Q={passive:!0};var Z={name:"eventListeners",enabled:!0,phase:"write",fn:function(){},effect:function(e){var n=e.state,r=e.instance,o=e.options,i=o.scroll,a=void 0===i||i,s=o.resize,f=void 0===s||s,c=t(n.elements.popper),p=[].concat(n.scrollParents.reference,n.scrollParents.popper);return a&&p.forEach((function(e){e.addEventListener("scroll",r.update,Q)})),f&&c.addEventListener("resize",r.update,Q),function(){a&&p.forEach((function(e){e.removeEventListener("scroll",r.update,Q)})),f&&c.removeEventListener("resize",r.update,Q)}},data:{}};var $={name:"popperOffsets",enabled:!0,phase:"read",fn:function(e){var t=e.state,n=e.name;t.modifiersData[n]=U({reference:t.rects.reference,element:t.rects.popper,strategy:"absolute",placement:t.placement})},data:{}},ee={top:"auto",right:"auto",bottom:"auto",left:"auto"};function te(e){var n,r=e.popper,o=e.popperRect,i=e.placement,a=e.variation,f=e.offsets,c=e.position,p=e.gpuAcceleration,l=e.adaptive,h=e.roundOffsets,m=e.isFixed,v=f.x,g=void 0===v?0:v,y=f.y,b=void 0===y?0:y,x="function"==typeof h?h({x:g,y:b}):{x:g,y:b};g=x.x,b=x.y;var w=f.hasOwnProperty("x"),L=f.hasOwnProperty("y"),P=A,M=j,W=window;if(l){var B=O(r),H="clientHeight",T="clientWidth";if(B===t(r)&&"static"!==d(B=u(r)).position&&"absolute"===c&&(H="scrollHeight",T="scrollWidth"),B=B,i===j||(i===A||i===D)&&a===k)M=E,b-=(m&&B===W&&W.visualViewport?W.visualViewport.height:B[H])-o.height,b*=p?1:-1;if(i===A||(i===j||i===E)&&a===k)P=D,g-=(m&&B===W&&W.visualViewport?W.visualViewport.width:B[T])-o.width,g*=p?1:-1}var R,S=Object.assign({position:c},l&&ee),C=!0===h?function(e){var t=e.x,n=e.y,r=window.devicePixelRatio||1;return{x:s(t*r)/r||0,y:s(n*r)/r||0}}({x:g,y:b}):{x:g,y:b};return g=C.x,b=C.y,p?Object.assign({},S,((R={})[M]=L?"0":"",R[P]=w?"0":"",R.transform=(W.devicePixelRatio||1)<=1?"translate("+g+"px, "+b+"px)":"translate3d("+g+"px, "+b+"px, 0)",R)):Object.assign({},S,((n={})[M]=L?b+"px":"",n[P]=w?g+"px":"",n.transform="",n))}var ne={name:"computeStyles",enabled:!0,phase:"beforeWrite",fn:function(e){var t=e.state,n=e.options,r=n.gpuAcceleration,o=void 0===r||r,i=n.adaptive,a=void 0===i||i,s=n.roundOffsets,f=void 0===s||s,c={placement:C(t.placement),variation:_(t.placement),popper:t.elements.popper,popperRect:t.rects.popper,gpuAcceleration:o,isFixed:"fixed"===t.options.strategy};null!=t.modifiersData.popperOffsets&&(t.styles.popper=Object.assign({},t.styles.popper,te(Object.assign({},c,{offsets:t.modifiersData.popperOffsets,position:t.options.strategy,adaptive:a,roundOffsets:f})))),null!=t.modifiersData.arrow&&(t.styles.arrow=Object.assign({},t.styles.arrow,te(Object.assign({},c,{offsets:t.modifiersData.arrow,position:"absolute",adaptive:!1,roundOffsets:f})))),t.attributes.popper=Object.assign({},t.attributes.popper,{"data-popper-placement":t.placement})},data:{}};var re={name:"applyStyles",enabled:!0,phase:"write",fn:function(e){var t=e.state;Object.keys(t.elements).forEach((function(e){var n=t.styles[e]||{},o=t.attributes[e]||{},i=t.elements[e];r(i)&&p(i)&&(Object.assign(i.style,n),Object.keys(o).forEach((function(e){var t=o[e];!1===t?i.removeAttribute(e):i.setAttribute(e,!0===t?"":t)})))}))},effect:function(e){var t=e.state,n={popper:{position:t.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};return Object.assign(t.elements.popper.style,n.popper),t.styles=n,t.elements.arrow&&Object.assign(t.elements.arrow.style,n.arrow),function(){Object.keys(t.elements).forEach((function(e){var o=t.elements[e],i=t.attributes[e]||{},a=Object.keys(t.styles.hasOwnProperty(e)?t.styles[e]:n[e]).reduce((function(e,t){return e[t]="",e}),{});r(o)&&p(o)&&(Object.assign(o.style,a),Object.keys(i).forEach((function(e){o.removeAttribute(e)})))}))}},requires:["computeStyles"]};var oe={name:"offset",enabled:!0,phase:"main",requires:["popperOffsets"],fn:function(e){var t=e.state,n=e.options,r=e.name,o=n.offset,i=void 0===o?[0,0]:o,a=T.reduce((function(e,n){return e[n]=function(e,t,n){var r=C(e),o=[A,j].indexOf(r)>=0?-1:1,i="function"==typeof n?n(Object.assign({},t,{placement:e})):n,a=i[0],s=i[1];return a=a||0,s=(s||0)*o,[A,D].indexOf(r)>=0?{x:s,y:a}:{x:a,y:s}}(n,t.rects,i),e}),{}),s=a[t.placement],f=s.x,c=s.y;null!=t.modifiersData.popperOffsets&&(t.modifiersData.popperOffsets.x+=f,t.modifiersData.popperOffsets.y+=c),t.modifiersData[r]=a}},ie={left:"right",right:"left",bottom:"top",top:"bottom"};function ae(e){return e.replace(/left|right|bottom|top/g,(function(e){return ie[e]}))}var se={start:"end",end:"start"};function fe(e){return e.replace(/start|end/g,(function(e){return se[e]}))}function ce(e,t){void 0===t&&(t={});var n=t,r=n.placement,o=n.boundary,i=n.rootBoundary,a=n.padding,s=n.flipVariations,f=n.allowedAutoPlacements,c=void 0===f?T:f,p=_(r),u=p?s?H:H.filter((function(e){return _(e)===p})):P,l=u.filter((function(e){return c.indexOf(e)>=0}));0===l.length&&(l=u);var d=l.reduce((function(t,n){return t[n]=Y(e,{placement:n,boundary:o,rootBoundary:i,padding:a})[C(n)],t}),{});return Object.keys(d).sort((function(e,t){return d[e]-d[t]}))}var pe={name:"flip",enabled:!0,phase:"main",fn:function(e){var t=e.state,n=e.options,r=e.name;if(!t.modifiersData[r]._skip){for(var o=n.mainAxis,i=void 0===o||o,a=n.altAxis,s=void 0===a||a,f=n.fallbackPlacements,c=n.padding,p=n.boundary,u=n.rootBoundary,l=n.altBoundary,d=n.flipVariations,h=void 0===d||d,m=n.allowedAutoPlacements,v=t.options.placement,g=C(v),y=f||(g===v||!h?[ae(v)]:function(e){if(C(e)===L)return[];var t=ae(e);return[fe(e),t,fe(t)]}(v)),b=[v].concat(y).reduce((function(e,n){return e.concat(C(n)===L?ce(t,{placement:n,boundary:p,rootBoundary:u,padding:c,flipVariations:h,allowedAutoPlacements:m}):n)}),[]),x=t.rects.reference,w=t.rects.popper,O=new Map,P=!0,k=b[0],W=0;W<b.length;W++){var B=b[W],H=C(B),T=_(B)===M,R=[j,E].indexOf(H)>=0,S=R?"width":"height",q=Y(t,{placement:B,boundary:p,rootBoundary:u,altBoundary:l,padding:c}),V=R?T?D:A:T?E:j;x[S]>w[S]&&(V=ae(V));var N=ae(V),I=[];if(i&&I.push(q[H]<=0),s&&I.push(q[V]<=0,q[N]<=0),I.every((function(e){return e}))){k=B,P=!1;break}O.set(B,I)}if(P)for(var F=function(e){var t=b.find((function(t){var n=O.get(t);if(n)return n.slice(0,e).every((function(e){return e}))}));if(t)return k=t,"break"},U=h?3:1;U>0;U--){if("break"===F(U))break}t.placement!==k&&(t.modifiersData[r]._skip=!0,t.placement=k,t.reset=!0)}},requiresIfExists:["offset"],data:{_skip:!1}};function ue(e,t,n){return i(e,a(t,n))}var le={name:"preventOverflow",enabled:!0,phase:"main",fn:function(e){var t=e.state,n=e.options,r=e.name,o=n.mainAxis,s=void 0===o||o,f=n.altAxis,c=void 0!==f&&f,p=n.boundary,u=n.rootBoundary,l=n.altBoundary,d=n.padding,h=n.tether,m=void 0===h||h,g=n.tetherOffset,y=void 0===g?0:g,b=Y(t,{boundary:p,rootBoundary:u,padding:d,altBoundary:l}),x=C(t.placement),w=_(t.placement),L=!w,P=F(x),k="x"===P?"y":"x",W=t.modifiersData.popperOffsets,B=t.rects.reference,H=t.rects.popper,T="function"==typeof y?y(Object.assign({},t.rects,{placement:t.placement})):y,R="number"==typeof T?{mainAxis:T,altAxis:T}:Object.assign({mainAxis:0,altAxis:0},T),S=t.modifiersData.offset?t.modifiersData.offset[t.placement]:null,q={x:0,y:0};if(W){if(s){var V,N="y"===P?j:A,I="y"===P?E:D,U="y"===P?"height":"width",z=W[P],X=z+b[N],G=z-b[I],J=m?-H[U]/2:0,K=w===M?B[U]:H[U],Q=w===M?-H[U]:-B[U],Z=t.elements.arrow,$=m&&Z?v(Z):{width:0,height:0},ee=t.modifiersData["arrow#persistent"]?t.modifiersData["arrow#persistent"].padding:{top:0,right:0,bottom:0,left:0},te=ee[N],ne=ee[I],re=ue(0,B[U],$[U]),oe=L?B[U]/2-J-re-te-R.mainAxis:K-re-te-R.mainAxis,ie=L?-B[U]/2+J+re+ne+R.mainAxis:Q+re+ne+R.mainAxis,ae=t.elements.arrow&&O(t.elements.arrow),se=ae?"y"===P?ae.clientTop||0:ae.clientLeft||0:0,fe=null!=(V=null==S?void 0:S[P])?V:0,ce=z+ie-fe,pe=ue(m?a(X,z+oe-fe-se):X,z,m?i(G,ce):G);W[P]=pe,q[P]=pe-z}if(c){var le,de="x"===P?j:A,he="x"===P?E:D,me=W[k],ve="y"===k?"height":"width",ge=me+b[de],ye=me-b[he],be=-1!==[j,A].indexOf(x),xe=null!=(le=null==S?void 0:S[k])?le:0,we=be?ge:me-B[ve]-H[ve]-xe+R.altAxis,Oe=be?me+B[ve]+H[ve]-xe-R.altAxis:ye,je=m&&be?function(e,t,n){var r=ue(e,t,n);return r>n?n:r}(we,me,Oe):ue(m?we:ge,me,m?Oe:ye);W[k]=je,q[k]=je-me}t.modifiersData[r]=q}},requiresIfExists:["offset"]};var de={name:"arrow",enabled:!0,phase:"main",fn:function(e){var t,n=e.state,r=e.name,o=e.options,i=n.elements.arrow,a=n.modifiersData.popperOffsets,s=C(n.placement),f=F(s),c=[A,D].indexOf(s)>=0?"height":"width";if(i&&a){var p=function(e,t){return z("number"!=typeof(e="function"==typeof e?e(Object.assign({},t.rects,{placement:t.placement})):e)?e:X(e,P))}(o.padding,n),u=v(i),l="y"===f?j:A,d="y"===f?E:D,h=n.rects.reference[c]+n.rects.reference[f]-a[f]-n.rects.popper[c],m=a[f]-n.rects.reference[f],g=O(i),y=g?"y"===f?g.clientHeight||0:g.clientWidth||0:0,b=h/2-m/2,x=p[l],w=y-u[c]-p[d],L=y/2-u[c]/2+b,M=ue(x,L,w),k=f;n.modifiersData[r]=((t={})[k]=M,t.centerOffset=M-L,t)}},effect:function(e){var t=e.state,n=e.options.element,r=void 0===n?"[data-popper-arrow]":n;null!=r&&("string"!=typeof r||(r=t.elements.popper.querySelector(r)))&&q(t.elements.popper,r)&&(t.elements.arrow=r)},requires:["popperOffsets"],requiresIfExists:["preventOverflow"]};function he(e,t,n){return void 0===n&&(n={x:0,y:0}),{top:e.top-t.height-n.y,right:e.right-t.width+n.x,bottom:e.bottom-t.height+n.y,left:e.left-t.width-n.x}}function me(e){return[j,D,E,A].some((function(t){return e[t]>=0}))}var ve={name:"hide",enabled:!0,phase:"main",requiresIfExists:["preventOverflow"],fn:function(e){var t=e.state,n=e.name,r=t.rects.reference,o=t.rects.popper,i=t.modifiersData.preventOverflow,a=Y(t,{elementContext:"reference"}),s=Y(t,{altBoundary:!0}),f=he(a,r),c=he(s,o,i),p=me(f),u=me(c);t.modifiersData[n]={referenceClippingOffsets:f,popperEscapeOffsets:c,isReferenceHidden:p,hasPopperEscaped:u},t.attributes.popper=Object.assign({},t.attributes.popper,{"data-popper-reference-hidden":p,"data-popper-escaped":u})}},ge=K({defaultModifiers:[Z,$,ne,re]}),ye=[Z,$,ne,re,oe,pe,le,de,ve],be=K({defaultModifiers:ye});e.applyStyles=re,e.arrow=de,e.computeStyles=ne,e.createPopper=be,e.createPopperLite=ge,e.defaultModifiers=ye,e.detectOverflow=Y,e.eventListeners=Z,e.flip=pe,e.hide=ve,e.offset=oe,e.popperGenerator=K,e.popperOffsets=$,e.preventOverflow=le,Object.defineProperty(e,"__esModule",{value:!0})})); + diff --git a/site_libs/quarto-html/quarto-syntax-highlighting.css b/site_libs/quarto-html/quarto-syntax-highlighting.css new file mode 100644 index 00000000..d9fd98f0 --- /dev/null +++ b/site_libs/quarto-html/quarto-syntax-highlighting.css @@ -0,0 +1,203 @@ +/* quarto syntax highlight colors */ +:root { + --quarto-hl-ot-color: #003B4F; + --quarto-hl-at-color: #657422; + --quarto-hl-ss-color: #20794D; + --quarto-hl-an-color: #5E5E5E; + --quarto-hl-fu-color: #4758AB; + --quarto-hl-st-color: #20794D; + --quarto-hl-cf-color: #003B4F; + --quarto-hl-op-color: #5E5E5E; + --quarto-hl-er-color: #AD0000; + --quarto-hl-bn-color: #AD0000; + --quarto-hl-al-color: #AD0000; + --quarto-hl-va-color: #111111; + --quarto-hl-bu-color: inherit; + --quarto-hl-ex-color: inherit; + --quarto-hl-pp-color: #AD0000; + --quarto-hl-in-color: #5E5E5E; + --quarto-hl-vs-color: #20794D; + --quarto-hl-wa-color: #5E5E5E; + --quarto-hl-do-color: #5E5E5E; + --quarto-hl-im-color: #00769E; + --quarto-hl-ch-color: #20794D; + --quarto-hl-dt-color: #AD0000; + --quarto-hl-fl-color: #AD0000; + --quarto-hl-co-color: #5E5E5E; + --quarto-hl-cv-color: #5E5E5E; + --quarto-hl-cn-color: #8f5902; + --quarto-hl-sc-color: #5E5E5E; + --quarto-hl-dv-color: #AD0000; + --quarto-hl-kw-color: #003B4F; +} + +/* other quarto variables */ +:root { + --quarto-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; +} + +pre > code.sourceCode > span { + color: #003B4F; +} + +code span { + color: #003B4F; +} + +code.sourceCode > span { + color: #003B4F; +} + +div.sourceCode, +div.sourceCode pre.sourceCode { + color: #003B4F; +} + +code span.ot { + color: #003B4F; + font-style: inherit; +} + +code span.at { + color: #657422; + font-style: inherit; +} + +code span.ss { + color: #20794D; + font-style: inherit; +} + +code span.an { + color: #5E5E5E; + font-style: inherit; +} + +code span.fu { + color: #4758AB; + font-style: inherit; +} + +code span.st { + color: #20794D; + font-style: inherit; +} + +code span.cf { + color: #003B4F; + font-style: inherit; +} + +code span.op { + color: #5E5E5E; + font-style: inherit; +} + +code span.er { + color: #AD0000; + font-style: inherit; +} + +code span.bn { + color: #AD0000; + font-style: inherit; +} + +code span.al { + color: #AD0000; + font-style: inherit; +} + +code span.va { + color: #111111; + font-style: inherit; +} + +code span.bu { + font-style: inherit; +} + +code span.ex { + font-style: inherit; +} + +code span.pp { + color: #AD0000; + font-style: inherit; +} + +code span.in { + color: #5E5E5E; + font-style: inherit; +} + +code span.vs { + color: #20794D; + font-style: inherit; +} + +code span.wa { + color: #5E5E5E; + font-style: italic; +} + +code span.do { + color: #5E5E5E; + font-style: italic; +} + +code span.im { + color: #00769E; + font-style: inherit; +} + +code span.ch { + color: #20794D; + font-style: inherit; +} + +code span.dt { + color: #AD0000; + font-style: inherit; +} + +code span.fl { + color: #AD0000; + font-style: inherit; +} + +code span.co { + color: #5E5E5E; + font-style: inherit; +} + +code span.cv { + color: #5E5E5E; + font-style: italic; +} + +code span.cn { + color: #8f5902; + font-style: inherit; +} + +code span.sc { + color: #5E5E5E; + font-style: inherit; +} + +code span.dv { + color: #AD0000; + font-style: inherit; +} + +code span.kw { + color: #003B4F; + font-style: inherit; +} + +.prevent-inlining { + content: "</"; +} + +/*# sourceMappingURL=debc5d5d77c3f9108843748ff7464032.css.map */ diff --git a/site_libs/quarto-html/quarto.js b/site_libs/quarto-html/quarto.js new file mode 100644 index 00000000..c3935c7e --- /dev/null +++ b/site_libs/quarto-html/quarto.js @@ -0,0 +1,902 @@ +const sectionChanged = new CustomEvent("quarto-sectionChanged", { + detail: {}, + bubbles: true, + cancelable: false, + composed: false, +}); + +const layoutMarginEls = () => { + // Find any conflicting margin elements and add margins to the + // top to prevent overlap + const marginChildren = window.document.querySelectorAll( + ".column-margin.column-container > * " + ); + + let lastBottom = 0; + for (const marginChild of marginChildren) { + if (marginChild.offsetParent !== null) { + // clear the top margin so we recompute it + marginChild.style.marginTop = null; + const top = marginChild.getBoundingClientRect().top + window.scrollY; + console.log({ + childtop: marginChild.getBoundingClientRect().top, + scroll: window.scrollY, + top, + lastBottom, + }); + if (top < lastBottom) { + const margin = lastBottom - top; + marginChild.style.marginTop = `${margin}px`; + } + const styles = window.getComputedStyle(marginChild); + const marginTop = parseFloat(styles["marginTop"]); + + console.log({ + top, + height: marginChild.getBoundingClientRect().height, + marginTop, + total: top + marginChild.getBoundingClientRect().height + marginTop, + }); + lastBottom = top + marginChild.getBoundingClientRect().height + marginTop; + } + } +}; + +window.document.addEventListener("DOMContentLoaded", function (_event) { + // Recompute the position of margin elements anytime the body size changes + if (window.ResizeObserver) { + const resizeObserver = new window.ResizeObserver( + throttle(layoutMarginEls, 50) + ); + resizeObserver.observe(window.document.body); + } + + const tocEl = window.document.querySelector('nav.toc-active[role="doc-toc"]'); + const sidebarEl = window.document.getElementById("quarto-sidebar"); + const leftTocEl = window.document.getElementById("quarto-sidebar-toc-left"); + const marginSidebarEl = window.document.getElementById( + "quarto-margin-sidebar" + ); + // function to determine whether the element has a previous sibling that is active + const prevSiblingIsActiveLink = (el) => { + const sibling = el.previousElementSibling; + if (sibling && sibling.tagName === "A") { + return sibling.classList.contains("active"); + } else { + return false; + } + }; + + // fire slideEnter for bootstrap tab activations (for htmlwidget resize behavior) + function fireSlideEnter(e) { + const event = window.document.createEvent("Event"); + event.initEvent("slideenter", true, true); + window.document.dispatchEvent(event); + } + const tabs = window.document.querySelectorAll('a[data-bs-toggle="tab"]'); + tabs.forEach((tab) => { + tab.addEventListener("shown.bs.tab", fireSlideEnter); + }); + + // fire slideEnter for tabby tab activations (for htmlwidget resize behavior) + document.addEventListener("tabby", fireSlideEnter, false); + + // Track scrolling and mark TOC links as active + // get table of contents and sidebar (bail if we don't have at least one) + const tocLinks = tocEl + ? [...tocEl.querySelectorAll("a[data-scroll-target]")] + : []; + const makeActive = (link) => tocLinks[link].classList.add("active"); + const removeActive = (link) => tocLinks[link].classList.remove("active"); + const removeAllActive = () => + [...Array(tocLinks.length).keys()].forEach((link) => removeActive(link)); + + // activate the anchor for a section associated with this TOC entry + tocLinks.forEach((link) => { + link.addEventListener("click", () => { + if (link.href.indexOf("#") !== -1) { + const anchor = link.href.split("#")[1]; + const heading = window.document.querySelector( + `[data-anchor-id=${anchor}]` + ); + if (heading) { + // Add the class + heading.classList.add("reveal-anchorjs-link"); + + // function to show the anchor + const handleMouseout = () => { + heading.classList.remove("reveal-anchorjs-link"); + heading.removeEventListener("mouseout", handleMouseout); + }; + + // add a function to clear the anchor when the user mouses out of it + heading.addEventListener("mouseout", handleMouseout); + } + } + }); + }); + + const sections = tocLinks.map((link) => { + const target = link.getAttribute("data-scroll-target"); + if (target.startsWith("#")) { + return window.document.getElementById(decodeURI(`${target.slice(1)}`)); + } else { + return window.document.querySelector(decodeURI(`${target}`)); + } + }); + + const sectionMargin = 200; + let currentActive = 0; + // track whether we've initialized state the first time + let init = false; + + const updateActiveLink = () => { + // The index from bottom to top (e.g. reversed list) + let sectionIndex = -1; + if ( + window.innerHeight + window.pageYOffset >= + window.document.body.offsetHeight + ) { + sectionIndex = 0; + } else { + sectionIndex = [...sections].reverse().findIndex((section) => { + if (section) { + return window.pageYOffset >= section.offsetTop - sectionMargin; + } else { + return false; + } + }); + } + if (sectionIndex > -1) { + const current = sections.length - sectionIndex - 1; + if (current !== currentActive) { + removeAllActive(); + currentActive = current; + makeActive(current); + if (init) { + window.dispatchEvent(sectionChanged); + } + init = true; + } + } + }; + + const inHiddenRegion = (top, bottom, hiddenRegions) => { + for (const region of hiddenRegions) { + if (top <= region.bottom && bottom >= region.top) { + return true; + } + } + return false; + }; + + const categorySelector = "header.quarto-title-block .quarto-category"; + const activateCategories = (href) => { + // Find any categories + // Surround them with a link pointing back to: + // #category=Authoring + try { + const categoryEls = window.document.querySelectorAll(categorySelector); + for (const categoryEl of categoryEls) { + const categoryText = categoryEl.textContent; + if (categoryText) { + const link = `${href}#category=${encodeURIComponent(categoryText)}`; + const linkEl = window.document.createElement("a"); + linkEl.setAttribute("href", link); + for (const child of categoryEl.childNodes) { + linkEl.append(child); + } + categoryEl.appendChild(linkEl); + } + } + } catch { + // Ignore errors + } + }; + function hasTitleCategories() { + return window.document.querySelector(categorySelector) !== null; + } + + function offsetRelativeUrl(url) { + const offset = getMeta("quarto:offset"); + return offset ? offset + url : url; + } + + function offsetAbsoluteUrl(url) { + const offset = getMeta("quarto:offset"); + const baseUrl = new URL(offset, window.location); + + const projRelativeUrl = url.replace(baseUrl, ""); + if (projRelativeUrl.startsWith("/")) { + return projRelativeUrl; + } else { + return "/" + projRelativeUrl; + } + } + + // read a meta tag value + function getMeta(metaName) { + const metas = window.document.getElementsByTagName("meta"); + for (let i = 0; i < metas.length; i++) { + if (metas[i].getAttribute("name") === metaName) { + return metas[i].getAttribute("content"); + } + } + return ""; + } + + async function findAndActivateCategories() { + const currentPagePath = offsetAbsoluteUrl(window.location.href); + const response = await fetch(offsetRelativeUrl("listings.json")); + if (response.status == 200) { + return response.json().then(function (listingPaths) { + const listingHrefs = []; + for (const listingPath of listingPaths) { + const pathWithoutLeadingSlash = listingPath.listing.substring(1); + for (const item of listingPath.items) { + if ( + item === currentPagePath || + item === currentPagePath + "index.html" + ) { + // Resolve this path against the offset to be sure + // we already are using the correct path to the listing + // (this adjusts the listing urls to be rooted against + // whatever root the page is actually running against) + const relative = offsetRelativeUrl(pathWithoutLeadingSlash); + const baseUrl = window.location; + const resolvedPath = new URL(relative, baseUrl); + listingHrefs.push(resolvedPath.pathname); + break; + } + } + } + + // Look up the tree for a nearby linting and use that if we find one + const nearestListing = findNearestParentListing( + offsetAbsoluteUrl(window.location.pathname), + listingHrefs + ); + if (nearestListing) { + activateCategories(nearestListing); + } else { + // See if the referrer is a listing page for this item + const referredRelativePath = offsetAbsoluteUrl(document.referrer); + const referrerListing = listingHrefs.find((listingHref) => { + const isListingReferrer = + listingHref === referredRelativePath || + listingHref === referredRelativePath + "index.html"; + return isListingReferrer; + }); + + if (referrerListing) { + // Try to use the referrer if possible + activateCategories(referrerListing); + } else if (listingHrefs.length > 0) { + // Otherwise, just fall back to the first listing + activateCategories(listingHrefs[0]); + } + } + }); + } + } + if (hasTitleCategories()) { + findAndActivateCategories(); + } + + const findNearestParentListing = (href, listingHrefs) => { + if (!href || !listingHrefs) { + return undefined; + } + // Look up the tree for a nearby linting and use that if we find one + const relativeParts = href.substring(1).split("/"); + while (relativeParts.length > 0) { + const path = relativeParts.join("/"); + for (const listingHref of listingHrefs) { + if (listingHref.startsWith(path)) { + return listingHref; + } + } + relativeParts.pop(); + } + + return undefined; + }; + + const manageSidebarVisiblity = (el, placeholderDescriptor) => { + let isVisible = true; + let elRect; + + return (hiddenRegions) => { + if (el === null) { + return; + } + + // Find the last element of the TOC + const lastChildEl = el.lastElementChild; + + if (lastChildEl) { + // Converts the sidebar to a menu + const convertToMenu = () => { + for (const child of el.children) { + child.style.opacity = 0; + child.style.overflow = "hidden"; + } + + nexttick(() => { + const toggleContainer = window.document.createElement("div"); + toggleContainer.style.width = "100%"; + toggleContainer.classList.add("zindex-over-content"); + toggleContainer.classList.add("quarto-sidebar-toggle"); + toggleContainer.classList.add("headroom-target"); // Marks this to be managed by headeroom + toggleContainer.id = placeholderDescriptor.id; + toggleContainer.style.position = "fixed"; + + const toggleIcon = window.document.createElement("i"); + toggleIcon.classList.add("quarto-sidebar-toggle-icon"); + toggleIcon.classList.add("bi"); + toggleIcon.classList.add("bi-caret-down-fill"); + + const toggleTitle = window.document.createElement("div"); + const titleEl = window.document.body.querySelector( + placeholderDescriptor.titleSelector + ); + if (titleEl) { + toggleTitle.append( + titleEl.textContent || titleEl.innerText, + toggleIcon + ); + } + toggleTitle.classList.add("zindex-over-content"); + toggleTitle.classList.add("quarto-sidebar-toggle-title"); + toggleContainer.append(toggleTitle); + + const toggleContents = window.document.createElement("div"); + toggleContents.classList = el.classList; + toggleContents.classList.add("zindex-over-content"); + toggleContents.classList.add("quarto-sidebar-toggle-contents"); + for (const child of el.children) { + if (child.id === "toc-title") { + continue; + } + + const clone = child.cloneNode(true); + clone.style.opacity = 1; + clone.style.display = null; + toggleContents.append(clone); + } + toggleContents.style.height = "0px"; + const positionToggle = () => { + // position the element (top left of parent, same width as parent) + if (!elRect) { + elRect = el.getBoundingClientRect(); + } + toggleContainer.style.left = `${elRect.left}px`; + toggleContainer.style.top = `${elRect.top}px`; + toggleContainer.style.width = `${elRect.width}px`; + }; + positionToggle(); + + toggleContainer.append(toggleContents); + el.parentElement.prepend(toggleContainer); + + // Process clicks + let tocShowing = false; + // Allow the caller to control whether this is dismissed + // when it is clicked (e.g. sidebar navigation supports + // opening and closing the nav tree, so don't dismiss on click) + const clickEl = placeholderDescriptor.dismissOnClick + ? toggleContainer + : toggleTitle; + + const closeToggle = () => { + if (tocShowing) { + toggleContainer.classList.remove("expanded"); + toggleContents.style.height = "0px"; + tocShowing = false; + } + }; + + // Get rid of any expanded toggle if the user scrolls + window.document.addEventListener( + "scroll", + throttle(() => { + closeToggle(); + }, 50) + ); + + // Handle positioning of the toggle + window.addEventListener( + "resize", + throttle(() => { + elRect = undefined; + positionToggle(); + }, 50) + ); + + window.addEventListener("quarto-hrChanged", () => { + elRect = undefined; + }); + + // Process the click + clickEl.onclick = () => { + if (!tocShowing) { + toggleContainer.classList.add("expanded"); + toggleContents.style.height = null; + tocShowing = true; + } else { + closeToggle(); + } + }; + }); + }; + + // Converts a sidebar from a menu back to a sidebar + const convertToSidebar = () => { + for (const child of el.children) { + child.style.opacity = 1; + child.style.overflow = null; + } + + const placeholderEl = window.document.getElementById( + placeholderDescriptor.id + ); + if (placeholderEl) { + placeholderEl.remove(); + } + + el.classList.remove("rollup"); + }; + + if (isReaderMode()) { + convertToMenu(); + isVisible = false; + } else { + // Find the top and bottom o the element that is being managed + const elTop = el.offsetTop; + const elBottom = + elTop + lastChildEl.offsetTop + lastChildEl.offsetHeight; + + if (!isVisible) { + // If the element is current not visible reveal if there are + // no conflicts with overlay regions + if (!inHiddenRegion(elTop, elBottom, hiddenRegions)) { + convertToSidebar(); + isVisible = true; + } + } else { + // If the element is visible, hide it if it conflicts with overlay regions + // and insert a placeholder toggle (or if we're in reader mode) + if (inHiddenRegion(elTop, elBottom, hiddenRegions)) { + convertToMenu(); + isVisible = false; + } + } + } + } + }; + }; + + const tabEls = document.querySelectorAll('a[data-bs-toggle="tab"]'); + for (const tabEl of tabEls) { + const id = tabEl.getAttribute("data-bs-target"); + if (id) { + const columnEl = document.querySelector( + `${id} .column-margin, .tabset-margin-content` + ); + if (columnEl) + tabEl.addEventListener("shown.bs.tab", function (event) { + const el = event.srcElement; + if (el) { + const visibleCls = `${el.id}-margin-content`; + // walk up until we find a parent tabset + let panelTabsetEl = el.parentElement; + while (panelTabsetEl) { + if (panelTabsetEl.classList.contains("panel-tabset")) { + break; + } + panelTabsetEl = panelTabsetEl.parentElement; + } + + if (panelTabsetEl) { + const prevSib = panelTabsetEl.previousElementSibling; + if ( + prevSib && + prevSib.classList.contains("tabset-margin-container") + ) { + const childNodes = prevSib.querySelectorAll( + ".tabset-margin-content" + ); + for (const childEl of childNodes) { + if (childEl.classList.contains(visibleCls)) { + childEl.classList.remove("collapse"); + } else { + childEl.classList.add("collapse"); + } + } + } + } + } + + layoutMarginEls(); + }); + } + } + + // Manage the visibility of the toc and the sidebar + const marginScrollVisibility = manageSidebarVisiblity(marginSidebarEl, { + id: "quarto-toc-toggle", + titleSelector: "#toc-title", + dismissOnClick: true, + }); + const sidebarScrollVisiblity = manageSidebarVisiblity(sidebarEl, { + id: "quarto-sidebarnav-toggle", + titleSelector: ".title", + dismissOnClick: false, + }); + let tocLeftScrollVisibility; + if (leftTocEl) { + tocLeftScrollVisibility = manageSidebarVisiblity(leftTocEl, { + id: "quarto-lefttoc-toggle", + titleSelector: "#toc-title", + dismissOnClick: true, + }); + } + + // Find the first element that uses formatting in special columns + const conflictingEls = window.document.body.querySelectorAll( + '[class^="column-"], [class*=" column-"], aside, [class*="margin-caption"], [class*=" margin-caption"], [class*="margin-ref"], [class*=" margin-ref"]' + ); + + // Filter all the possibly conflicting elements into ones + // the do conflict on the left or ride side + const arrConflictingEls = Array.from(conflictingEls); + const leftSideConflictEls = arrConflictingEls.filter((el) => { + if (el.tagName === "ASIDE") { + return false; + } + return Array.from(el.classList).find((className) => { + return ( + className !== "column-body" && + className.startsWith("column-") && + !className.endsWith("right") && + !className.endsWith("container") && + className !== "column-margin" + ); + }); + }); + const rightSideConflictEls = arrConflictingEls.filter((el) => { + if (el.tagName === "ASIDE") { + return true; + } + + const hasMarginCaption = Array.from(el.classList).find((className) => { + return className == "margin-caption"; + }); + if (hasMarginCaption) { + return true; + } + + return Array.from(el.classList).find((className) => { + return ( + className !== "column-body" && + !className.endsWith("container") && + className.startsWith("column-") && + !className.endsWith("left") + ); + }); + }); + + const kOverlapPaddingSize = 10; + function toRegions(els) { + return els.map((el) => { + const boundRect = el.getBoundingClientRect(); + const top = + boundRect.top + + document.documentElement.scrollTop - + kOverlapPaddingSize; + return { + top, + bottom: top + el.scrollHeight + 2 * kOverlapPaddingSize, + }; + }); + } + + let hasObserved = false; + const visibleItemObserver = (els) => { + let visibleElements = [...els]; + const intersectionObserver = new IntersectionObserver( + (entries, _observer) => { + entries.forEach((entry) => { + if (entry.isIntersecting) { + if (visibleElements.indexOf(entry.target) === -1) { + visibleElements.push(entry.target); + } + } else { + visibleElements = visibleElements.filter((visibleEntry) => { + return visibleEntry !== entry; + }); + } + }); + + if (!hasObserved) { + hideOverlappedSidebars(); + } + hasObserved = true; + }, + {} + ); + els.forEach((el) => { + intersectionObserver.observe(el); + }); + + return { + getVisibleEntries: () => { + return visibleElements; + }, + }; + }; + + const rightElementObserver = visibleItemObserver(rightSideConflictEls); + const leftElementObserver = visibleItemObserver(leftSideConflictEls); + + const hideOverlappedSidebars = () => { + marginScrollVisibility(toRegions(rightElementObserver.getVisibleEntries())); + sidebarScrollVisiblity(toRegions(leftElementObserver.getVisibleEntries())); + if (tocLeftScrollVisibility) { + tocLeftScrollVisibility( + toRegions(leftElementObserver.getVisibleEntries()) + ); + } + }; + + window.quartoToggleReader = () => { + // Applies a slow class (or removes it) + // to update the transition speed + const slowTransition = (slow) => { + const manageTransition = (id, slow) => { + const el = document.getElementById(id); + if (el) { + if (slow) { + el.classList.add("slow"); + } else { + el.classList.remove("slow"); + } + } + }; + + manageTransition("TOC", slow); + manageTransition("quarto-sidebar", slow); + }; + const readerMode = !isReaderMode(); + setReaderModeValue(readerMode); + + // If we're entering reader mode, slow the transition + if (readerMode) { + slowTransition(readerMode); + } + highlightReaderToggle(readerMode); + hideOverlappedSidebars(); + + // If we're exiting reader mode, restore the non-slow transition + if (!readerMode) { + slowTransition(!readerMode); + } + }; + + const highlightReaderToggle = (readerMode) => { + const els = document.querySelectorAll(".quarto-reader-toggle"); + if (els) { + els.forEach((el) => { + if (readerMode) { + el.classList.add("reader"); + } else { + el.classList.remove("reader"); + } + }); + } + }; + + const setReaderModeValue = (val) => { + if (window.location.protocol !== "file:") { + window.localStorage.setItem("quarto-reader-mode", val); + } else { + localReaderMode = val; + } + }; + + const isReaderMode = () => { + if (window.location.protocol !== "file:") { + return window.localStorage.getItem("quarto-reader-mode") === "true"; + } else { + return localReaderMode; + } + }; + let localReaderMode = null; + + const tocOpenDepthStr = tocEl?.getAttribute("data-toc-expanded"); + const tocOpenDepth = tocOpenDepthStr ? Number(tocOpenDepthStr) : 1; + + // Walk the TOC and collapse/expand nodes + // Nodes are expanded if: + // - they are top level + // - they have children that are 'active' links + // - they are directly below an link that is 'active' + const walk = (el, depth) => { + // Tick depth when we enter a UL + if (el.tagName === "UL") { + depth = depth + 1; + } + + // It this is active link + let isActiveNode = false; + if (el.tagName === "A" && el.classList.contains("active")) { + isActiveNode = true; + } + + // See if there is an active child to this element + let hasActiveChild = false; + for (child of el.children) { + hasActiveChild = walk(child, depth) || hasActiveChild; + } + + // Process the collapse state if this is an UL + if (el.tagName === "UL") { + if (tocOpenDepth === -1 && depth > 1) { + el.classList.add("collapse"); + } else if ( + depth <= tocOpenDepth || + hasActiveChild || + prevSiblingIsActiveLink(el) + ) { + el.classList.remove("collapse"); + } else { + el.classList.add("collapse"); + } + + // untick depth when we leave a UL + depth = depth - 1; + } + return hasActiveChild || isActiveNode; + }; + + // walk the TOC and expand / collapse any items that should be shown + + if (tocEl) { + walk(tocEl, 0); + updateActiveLink(); + } + + // Throttle the scroll event and walk peridiocally + window.document.addEventListener( + "scroll", + throttle(() => { + if (tocEl) { + updateActiveLink(); + walk(tocEl, 0); + } + if (!isReaderMode()) { + hideOverlappedSidebars(); + } + }, 5) + ); + window.addEventListener( + "resize", + throttle(() => { + if (!isReaderMode()) { + hideOverlappedSidebars(); + } + }, 10) + ); + hideOverlappedSidebars(); + highlightReaderToggle(isReaderMode()); +}); + +// grouped tabsets +window.addEventListener("pageshow", (_event) => { + function getTabSettings() { + const data = localStorage.getItem("quarto-persistent-tabsets-data"); + if (!data) { + localStorage.setItem("quarto-persistent-tabsets-data", "{}"); + return {}; + } + if (data) { + return JSON.parse(data); + } + } + + function setTabSettings(data) { + localStorage.setItem( + "quarto-persistent-tabsets-data", + JSON.stringify(data) + ); + } + + function setTabState(groupName, groupValue) { + const data = getTabSettings(); + data[groupName] = groupValue; + setTabSettings(data); + } + + function toggleTab(tab, active) { + const tabPanelId = tab.getAttribute("aria-controls"); + const tabPanel = document.getElementById(tabPanelId); + if (active) { + tab.classList.add("active"); + tabPanel.classList.add("active"); + } else { + tab.classList.remove("active"); + tabPanel.classList.remove("active"); + } + } + + function toggleAll(selectedGroup, selectorsToSync) { + for (const [thisGroup, tabs] of Object.entries(selectorsToSync)) { + const active = selectedGroup === thisGroup; + for (const tab of tabs) { + toggleTab(tab, active); + } + } + } + + function findSelectorsToSyncByLanguage() { + const result = {}; + const tabs = Array.from( + document.querySelectorAll(`div[data-group] a[id^='tabset-']`) + ); + for (const item of tabs) { + const div = item.parentElement.parentElement.parentElement; + const group = div.getAttribute("data-group"); + if (!result[group]) { + result[group] = {}; + } + const selectorsToSync = result[group]; + const value = item.innerHTML; + if (!selectorsToSync[value]) { + selectorsToSync[value] = []; + } + selectorsToSync[value].push(item); + } + return result; + } + + function setupSelectorSync() { + const selectorsToSync = findSelectorsToSyncByLanguage(); + Object.entries(selectorsToSync).forEach(([group, tabSetsByValue]) => { + Object.entries(tabSetsByValue).forEach(([value, items]) => { + items.forEach((item) => { + item.addEventListener("click", (_event) => { + setTabState(group, value); + toggleAll(value, selectorsToSync[group]); + }); + }); + }); + }); + return selectorsToSync; + } + + const selectorsToSync = setupSelectorSync(); + for (const [group, selectedName] of Object.entries(getTabSettings())) { + const selectors = selectorsToSync[group]; + // it's possible that stale state gives us empty selections, so we explicitly check here. + if (selectors) { + toggleAll(selectedName, selectors); + } + } +}); + +function throttle(func, wait) { + let waiting = false; + return function () { + if (!waiting) { + func.apply(this, arguments); + waiting = true; + setTimeout(function () { + waiting = false; + }, wait); + } + }; +} + +function nexttick(func) { + return setTimeout(func, 0); +} diff --git a/site_libs/quarto-html/tippy.css b/site_libs/quarto-html/tippy.css new file mode 100644 index 00000000..e6ae635c --- /dev/null +++ b/site_libs/quarto-html/tippy.css @@ -0,0 +1 @@ +.tippy-box[data-animation=fade][data-state=hidden]{opacity:0}[data-tippy-root]{max-width:calc(100vw - 10px)}.tippy-box{position:relative;background-color:#333;color:#fff;border-radius:4px;font-size:14px;line-height:1.4;white-space:normal;outline:0;transition-property:transform,visibility,opacity}.tippy-box[data-placement^=top]>.tippy-arrow{bottom:0}.tippy-box[data-placement^=top]>.tippy-arrow:before{bottom:-7px;left:0;border-width:8px 8px 0;border-top-color:initial;transform-origin:center top}.tippy-box[data-placement^=bottom]>.tippy-arrow{top:0}.tippy-box[data-placement^=bottom]>.tippy-arrow:before{top:-7px;left:0;border-width:0 8px 8px;border-bottom-color:initial;transform-origin:center bottom}.tippy-box[data-placement^=left]>.tippy-arrow{right:0}.tippy-box[data-placement^=left]>.tippy-arrow:before{border-width:8px 0 8px 8px;border-left-color:initial;right:-7px;transform-origin:center left}.tippy-box[data-placement^=right]>.tippy-arrow{left:0}.tippy-box[data-placement^=right]>.tippy-arrow:before{left:-7px;border-width:8px 8px 8px 0;border-right-color:initial;transform-origin:center right}.tippy-box[data-inertia][data-state=visible]{transition-timing-function:cubic-bezier(.54,1.5,.38,1.11)}.tippy-arrow{width:16px;height:16px;color:#333}.tippy-arrow:before{content:"";position:absolute;border-color:transparent;border-style:solid}.tippy-content{position:relative;padding:5px 9px;z-index:1} \ No newline at end of file diff --git a/site_libs/quarto-html/tippy.umd.min.js b/site_libs/quarto-html/tippy.umd.min.js new file mode 100644 index 00000000..ca292be3 --- /dev/null +++ b/site_libs/quarto-html/tippy.umd.min.js @@ -0,0 +1,2 @@ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("@popperjs/core")):"function"==typeof define&&define.amd?define(["@popperjs/core"],t):(e=e||self).tippy=t(e.Popper)}(this,(function(e){"use strict";var t={passive:!0,capture:!0},n=function(){return document.body};function r(e,t,n){if(Array.isArray(e)){var r=e[t];return null==r?Array.isArray(n)?n[t]:n:r}return e}function o(e,t){var n={}.toString.call(e);return 0===n.indexOf("[object")&&n.indexOf(t+"]")>-1}function i(e,t){return"function"==typeof e?e.apply(void 0,t):e}function a(e,t){return 0===t?e:function(r){clearTimeout(n),n=setTimeout((function(){e(r)}),t)};var n}function s(e,t){var n=Object.assign({},e);return t.forEach((function(e){delete n[e]})),n}function u(e){return[].concat(e)}function c(e,t){-1===e.indexOf(t)&&e.push(t)}function p(e){return e.split("-")[0]}function f(e){return[].slice.call(e)}function l(e){return Object.keys(e).reduce((function(t,n){return void 0!==e[n]&&(t[n]=e[n]),t}),{})}function d(){return document.createElement("div")}function v(e){return["Element","Fragment"].some((function(t){return o(e,t)}))}function m(e){return o(e,"MouseEvent")}function g(e){return!(!e||!e._tippy||e._tippy.reference!==e)}function h(e){return v(e)?[e]:function(e){return o(e,"NodeList")}(e)?f(e):Array.isArray(e)?e:f(document.querySelectorAll(e))}function b(e,t){e.forEach((function(e){e&&(e.style.transitionDuration=t+"ms")}))}function y(e,t){e.forEach((function(e){e&&e.setAttribute("data-state",t)}))}function w(e){var t,n=u(e)[0];return null!=n&&null!=(t=n.ownerDocument)&&t.body?n.ownerDocument:document}function E(e,t,n){var r=t+"EventListener";["transitionend","webkitTransitionEnd"].forEach((function(t){e[r](t,n)}))}function O(e,t){for(var n=t;n;){var r;if(e.contains(n))return!0;n=null==n.getRootNode||null==(r=n.getRootNode())?void 0:r.host}return!1}var x={isTouch:!1},C=0;function T(){x.isTouch||(x.isTouch=!0,window.performance&&document.addEventListener("mousemove",A))}function A(){var e=performance.now();e-C<20&&(x.isTouch=!1,document.removeEventListener("mousemove",A)),C=e}function L(){var e=document.activeElement;if(g(e)){var t=e._tippy;e.blur&&!t.state.isVisible&&e.blur()}}var D=!!("undefined"!=typeof window&&"undefined"!=typeof document)&&!!window.msCrypto,R=Object.assign({appendTo:n,aria:{content:"auto",expanded:"auto"},delay:0,duration:[300,250],getReferenceClientRect:null,hideOnClick:!0,ignoreAttributes:!1,interactive:!1,interactiveBorder:2,interactiveDebounce:0,moveTransition:"",offset:[0,10],onAfterUpdate:function(){},onBeforeUpdate:function(){},onCreate:function(){},onDestroy:function(){},onHidden:function(){},onHide:function(){},onMount:function(){},onShow:function(){},onShown:function(){},onTrigger:function(){},onUntrigger:function(){},onClickOutside:function(){},placement:"top",plugins:[],popperOptions:{},render:null,showOnCreate:!1,touch:!0,trigger:"mouseenter focus",triggerTarget:null},{animateFill:!1,followCursor:!1,inlinePositioning:!1,sticky:!1},{allowHTML:!1,animation:"fade",arrow:!0,content:"",inertia:!1,maxWidth:350,role:"tooltip",theme:"",zIndex:9999}),k=Object.keys(R);function P(e){var t=(e.plugins||[]).reduce((function(t,n){var r,o=n.name,i=n.defaultValue;o&&(t[o]=void 0!==e[o]?e[o]:null!=(r=R[o])?r:i);return t}),{});return Object.assign({},e,t)}function j(e,t){var n=Object.assign({},t,{content:i(t.content,[e])},t.ignoreAttributes?{}:function(e,t){return(t?Object.keys(P(Object.assign({},R,{plugins:t}))):k).reduce((function(t,n){var r=(e.getAttribute("data-tippy-"+n)||"").trim();if(!r)return t;if("content"===n)t[n]=r;else try{t[n]=JSON.parse(r)}catch(e){t[n]=r}return t}),{})}(e,t.plugins));return n.aria=Object.assign({},R.aria,n.aria),n.aria={expanded:"auto"===n.aria.expanded?t.interactive:n.aria.expanded,content:"auto"===n.aria.content?t.interactive?null:"describedby":n.aria.content},n}function M(e,t){e.innerHTML=t}function V(e){var t=d();return!0===e?t.className="tippy-arrow":(t.className="tippy-svg-arrow",v(e)?t.appendChild(e):M(t,e)),t}function I(e,t){v(t.content)?(M(e,""),e.appendChild(t.content)):"function"!=typeof t.content&&(t.allowHTML?M(e,t.content):e.textContent=t.content)}function S(e){var t=e.firstElementChild,n=f(t.children);return{box:t,content:n.find((function(e){return e.classList.contains("tippy-content")})),arrow:n.find((function(e){return e.classList.contains("tippy-arrow")||e.classList.contains("tippy-svg-arrow")})),backdrop:n.find((function(e){return e.classList.contains("tippy-backdrop")}))}}function N(e){var t=d(),n=d();n.className="tippy-box",n.setAttribute("data-state","hidden"),n.setAttribute("tabindex","-1");var r=d();function o(n,r){var o=S(t),i=o.box,a=o.content,s=o.arrow;r.theme?i.setAttribute("data-theme",r.theme):i.removeAttribute("data-theme"),"string"==typeof r.animation?i.setAttribute("data-animation",r.animation):i.removeAttribute("data-animation"),r.inertia?i.setAttribute("data-inertia",""):i.removeAttribute("data-inertia"),i.style.maxWidth="number"==typeof r.maxWidth?r.maxWidth+"px":r.maxWidth,r.role?i.setAttribute("role",r.role):i.removeAttribute("role"),n.content===r.content&&n.allowHTML===r.allowHTML||I(a,e.props),r.arrow?s?n.arrow!==r.arrow&&(i.removeChild(s),i.appendChild(V(r.arrow))):i.appendChild(V(r.arrow)):s&&i.removeChild(s)}return r.className="tippy-content",r.setAttribute("data-state","hidden"),I(r,e.props),t.appendChild(n),n.appendChild(r),o(e.props,e.props),{popper:t,onUpdate:o}}N.$$tippy=!0;var B=1,H=[],U=[];function _(o,s){var v,g,h,C,T,A,L,k,M=j(o,Object.assign({},R,P(l(s)))),V=!1,I=!1,N=!1,_=!1,F=[],W=a(we,M.interactiveDebounce),X=B++,Y=(k=M.plugins).filter((function(e,t){return k.indexOf(e)===t})),$={id:X,reference:o,popper:d(),popperInstance:null,props:M,state:{isEnabled:!0,isVisible:!1,isDestroyed:!1,isMounted:!1,isShown:!1},plugins:Y,clearDelayTimeouts:function(){clearTimeout(v),clearTimeout(g),cancelAnimationFrame(h)},setProps:function(e){if($.state.isDestroyed)return;ae("onBeforeUpdate",[$,e]),be();var t=$.props,n=j(o,Object.assign({},t,l(e),{ignoreAttributes:!0}));$.props=n,he(),t.interactiveDebounce!==n.interactiveDebounce&&(ce(),W=a(we,n.interactiveDebounce));t.triggerTarget&&!n.triggerTarget?u(t.triggerTarget).forEach((function(e){e.removeAttribute("aria-expanded")})):n.triggerTarget&&o.removeAttribute("aria-expanded");ue(),ie(),J&&J(t,n);$.popperInstance&&(Ce(),Ae().forEach((function(e){requestAnimationFrame(e._tippy.popperInstance.forceUpdate)})));ae("onAfterUpdate",[$,e])},setContent:function(e){$.setProps({content:e})},show:function(){var e=$.state.isVisible,t=$.state.isDestroyed,o=!$.state.isEnabled,a=x.isTouch&&!$.props.touch,s=r($.props.duration,0,R.duration);if(e||t||o||a)return;if(te().hasAttribute("disabled"))return;if(ae("onShow",[$],!1),!1===$.props.onShow($))return;$.state.isVisible=!0,ee()&&(z.style.visibility="visible");ie(),de(),$.state.isMounted||(z.style.transition="none");if(ee()){var u=re(),p=u.box,f=u.content;b([p,f],0)}A=function(){var e;if($.state.isVisible&&!_){if(_=!0,z.offsetHeight,z.style.transition=$.props.moveTransition,ee()&&$.props.animation){var t=re(),n=t.box,r=t.content;b([n,r],s),y([n,r],"visible")}se(),ue(),c(U,$),null==(e=$.popperInstance)||e.forceUpdate(),ae("onMount",[$]),$.props.animation&&ee()&&function(e,t){me(e,t)}(s,(function(){$.state.isShown=!0,ae("onShown",[$])}))}},function(){var e,t=$.props.appendTo,r=te();e=$.props.interactive&&t===n||"parent"===t?r.parentNode:i(t,[r]);e.contains(z)||e.appendChild(z);$.state.isMounted=!0,Ce()}()},hide:function(){var e=!$.state.isVisible,t=$.state.isDestroyed,n=!$.state.isEnabled,o=r($.props.duration,1,R.duration);if(e||t||n)return;if(ae("onHide",[$],!1),!1===$.props.onHide($))return;$.state.isVisible=!1,$.state.isShown=!1,_=!1,V=!1,ee()&&(z.style.visibility="hidden");if(ce(),ve(),ie(!0),ee()){var i=re(),a=i.box,s=i.content;$.props.animation&&(b([a,s],o),y([a,s],"hidden"))}se(),ue(),$.props.animation?ee()&&function(e,t){me(e,(function(){!$.state.isVisible&&z.parentNode&&z.parentNode.contains(z)&&t()}))}(o,$.unmount):$.unmount()},hideWithInteractivity:function(e){ne().addEventListener("mousemove",W),c(H,W),W(e)},enable:function(){$.state.isEnabled=!0},disable:function(){$.hide(),$.state.isEnabled=!1},unmount:function(){$.state.isVisible&&$.hide();if(!$.state.isMounted)return;Te(),Ae().forEach((function(e){e._tippy.unmount()})),z.parentNode&&z.parentNode.removeChild(z);U=U.filter((function(e){return e!==$})),$.state.isMounted=!1,ae("onHidden",[$])},destroy:function(){if($.state.isDestroyed)return;$.clearDelayTimeouts(),$.unmount(),be(),delete o._tippy,$.state.isDestroyed=!0,ae("onDestroy",[$])}};if(!M.render)return $;var q=M.render($),z=q.popper,J=q.onUpdate;z.setAttribute("data-tippy-root",""),z.id="tippy-"+$.id,$.popper=z,o._tippy=$,z._tippy=$;var G=Y.map((function(e){return e.fn($)})),K=o.hasAttribute("aria-expanded");return he(),ue(),ie(),ae("onCreate",[$]),M.showOnCreate&&Le(),z.addEventListener("mouseenter",(function(){$.props.interactive&&$.state.isVisible&&$.clearDelayTimeouts()})),z.addEventListener("mouseleave",(function(){$.props.interactive&&$.props.trigger.indexOf("mouseenter")>=0&&ne().addEventListener("mousemove",W)})),$;function Q(){var e=$.props.touch;return Array.isArray(e)?e:[e,0]}function Z(){return"hold"===Q()[0]}function ee(){var e;return!(null==(e=$.props.render)||!e.$$tippy)}function te(){return L||o}function ne(){var e=te().parentNode;return e?w(e):document}function re(){return S(z)}function oe(e){return $.state.isMounted&&!$.state.isVisible||x.isTouch||C&&"focus"===C.type?0:r($.props.delay,e?0:1,R.delay)}function ie(e){void 0===e&&(e=!1),z.style.pointerEvents=$.props.interactive&&!e?"":"none",z.style.zIndex=""+$.props.zIndex}function ae(e,t,n){var r;(void 0===n&&(n=!0),G.forEach((function(n){n[e]&&n[e].apply(n,t)})),n)&&(r=$.props)[e].apply(r,t)}function se(){var e=$.props.aria;if(e.content){var t="aria-"+e.content,n=z.id;u($.props.triggerTarget||o).forEach((function(e){var r=e.getAttribute(t);if($.state.isVisible)e.setAttribute(t,r?r+" "+n:n);else{var o=r&&r.replace(n,"").trim();o?e.setAttribute(t,o):e.removeAttribute(t)}}))}}function ue(){!K&&$.props.aria.expanded&&u($.props.triggerTarget||o).forEach((function(e){$.props.interactive?e.setAttribute("aria-expanded",$.state.isVisible&&e===te()?"true":"false"):e.removeAttribute("aria-expanded")}))}function ce(){ne().removeEventListener("mousemove",W),H=H.filter((function(e){return e!==W}))}function pe(e){if(!x.isTouch||!N&&"mousedown"!==e.type){var t=e.composedPath&&e.composedPath()[0]||e.target;if(!$.props.interactive||!O(z,t)){if(u($.props.triggerTarget||o).some((function(e){return O(e,t)}))){if(x.isTouch)return;if($.state.isVisible&&$.props.trigger.indexOf("click")>=0)return}else ae("onClickOutside",[$,e]);!0===$.props.hideOnClick&&($.clearDelayTimeouts(),$.hide(),I=!0,setTimeout((function(){I=!1})),$.state.isMounted||ve())}}}function fe(){N=!0}function le(){N=!1}function de(){var e=ne();e.addEventListener("mousedown",pe,!0),e.addEventListener("touchend",pe,t),e.addEventListener("touchstart",le,t),e.addEventListener("touchmove",fe,t)}function ve(){var e=ne();e.removeEventListener("mousedown",pe,!0),e.removeEventListener("touchend",pe,t),e.removeEventListener("touchstart",le,t),e.removeEventListener("touchmove",fe,t)}function me(e,t){var n=re().box;function r(e){e.target===n&&(E(n,"remove",r),t())}if(0===e)return t();E(n,"remove",T),E(n,"add",r),T=r}function ge(e,t,n){void 0===n&&(n=!1),u($.props.triggerTarget||o).forEach((function(r){r.addEventListener(e,t,n),F.push({node:r,eventType:e,handler:t,options:n})}))}function he(){var e;Z()&&(ge("touchstart",ye,{passive:!0}),ge("touchend",Ee,{passive:!0})),(e=$.props.trigger,e.split(/\s+/).filter(Boolean)).forEach((function(e){if("manual"!==e)switch(ge(e,ye),e){case"mouseenter":ge("mouseleave",Ee);break;case"focus":ge(D?"focusout":"blur",Oe);break;case"focusin":ge("focusout",Oe)}}))}function be(){F.forEach((function(e){var t=e.node,n=e.eventType,r=e.handler,o=e.options;t.removeEventListener(n,r,o)})),F=[]}function ye(e){var t,n=!1;if($.state.isEnabled&&!xe(e)&&!I){var r="focus"===(null==(t=C)?void 0:t.type);C=e,L=e.currentTarget,ue(),!$.state.isVisible&&m(e)&&H.forEach((function(t){return t(e)})),"click"===e.type&&($.props.trigger.indexOf("mouseenter")<0||V)&&!1!==$.props.hideOnClick&&$.state.isVisible?n=!0:Le(e),"click"===e.type&&(V=!n),n&&!r&&De(e)}}function we(e){var t=e.target,n=te().contains(t)||z.contains(t);"mousemove"===e.type&&n||function(e,t){var n=t.clientX,r=t.clientY;return e.every((function(e){var t=e.popperRect,o=e.popperState,i=e.props.interactiveBorder,a=p(o.placement),s=o.modifiersData.offset;if(!s)return!0;var u="bottom"===a?s.top.y:0,c="top"===a?s.bottom.y:0,f="right"===a?s.left.x:0,l="left"===a?s.right.x:0,d=t.top-r+u>i,v=r-t.bottom-c>i,m=t.left-n+f>i,g=n-t.right-l>i;return d||v||m||g}))}(Ae().concat(z).map((function(e){var t,n=null==(t=e._tippy.popperInstance)?void 0:t.state;return n?{popperRect:e.getBoundingClientRect(),popperState:n,props:M}:null})).filter(Boolean),e)&&(ce(),De(e))}function Ee(e){xe(e)||$.props.trigger.indexOf("click")>=0&&V||($.props.interactive?$.hideWithInteractivity(e):De(e))}function Oe(e){$.props.trigger.indexOf("focusin")<0&&e.target!==te()||$.props.interactive&&e.relatedTarget&&z.contains(e.relatedTarget)||De(e)}function xe(e){return!!x.isTouch&&Z()!==e.type.indexOf("touch")>=0}function Ce(){Te();var t=$.props,n=t.popperOptions,r=t.placement,i=t.offset,a=t.getReferenceClientRect,s=t.moveTransition,u=ee()?S(z).arrow:null,c=a?{getBoundingClientRect:a,contextElement:a.contextElement||te()}:o,p=[{name:"offset",options:{offset:i}},{name:"preventOverflow",options:{padding:{top:2,bottom:2,left:5,right:5}}},{name:"flip",options:{padding:5}},{name:"computeStyles",options:{adaptive:!s}},{name:"$$tippy",enabled:!0,phase:"beforeWrite",requires:["computeStyles"],fn:function(e){var t=e.state;if(ee()){var n=re().box;["placement","reference-hidden","escaped"].forEach((function(e){"placement"===e?n.setAttribute("data-placement",t.placement):t.attributes.popper["data-popper-"+e]?n.setAttribute("data-"+e,""):n.removeAttribute("data-"+e)})),t.attributes.popper={}}}}];ee()&&u&&p.push({name:"arrow",options:{element:u,padding:3}}),p.push.apply(p,(null==n?void 0:n.modifiers)||[]),$.popperInstance=e.createPopper(c,z,Object.assign({},n,{placement:r,onFirstUpdate:A,modifiers:p}))}function Te(){$.popperInstance&&($.popperInstance.destroy(),$.popperInstance=null)}function Ae(){return f(z.querySelectorAll("[data-tippy-root]"))}function Le(e){$.clearDelayTimeouts(),e&&ae("onTrigger",[$,e]),de();var t=oe(!0),n=Q(),r=n[0],o=n[1];x.isTouch&&"hold"===r&&o&&(t=o),t?v=setTimeout((function(){$.show()}),t):$.show()}function De(e){if($.clearDelayTimeouts(),ae("onUntrigger",[$,e]),$.state.isVisible){if(!($.props.trigger.indexOf("mouseenter")>=0&&$.props.trigger.indexOf("click")>=0&&["mouseleave","mousemove"].indexOf(e.type)>=0&&V)){var t=oe(!1);t?g=setTimeout((function(){$.state.isVisible&&$.hide()}),t):h=requestAnimationFrame((function(){$.hide()}))}}else ve()}}function F(e,n){void 0===n&&(n={});var r=R.plugins.concat(n.plugins||[]);document.addEventListener("touchstart",T,t),window.addEventListener("blur",L);var o=Object.assign({},n,{plugins:r}),i=h(e).reduce((function(e,t){var n=t&&_(t,o);return n&&e.push(n),e}),[]);return v(e)?i[0]:i}F.defaultProps=R,F.setDefaultProps=function(e){Object.keys(e).forEach((function(t){R[t]=e[t]}))},F.currentInput=x;var W=Object.assign({},e.applyStyles,{effect:function(e){var t=e.state,n={popper:{position:t.options.strategy,left:"0",top:"0",margin:"0"},arrow:{position:"absolute"},reference:{}};Object.assign(t.elements.popper.style,n.popper),t.styles=n,t.elements.arrow&&Object.assign(t.elements.arrow.style,n.arrow)}}),X={mouseover:"mouseenter",focusin:"focus",click:"click"};var Y={name:"animateFill",defaultValue:!1,fn:function(e){var t;if(null==(t=e.props.render)||!t.$$tippy)return{};var n=S(e.popper),r=n.box,o=n.content,i=e.props.animateFill?function(){var e=d();return e.className="tippy-backdrop",y([e],"hidden"),e}():null;return{onCreate:function(){i&&(r.insertBefore(i,r.firstElementChild),r.setAttribute("data-animatefill",""),r.style.overflow="hidden",e.setProps({arrow:!1,animation:"shift-away"}))},onMount:function(){if(i){var e=r.style.transitionDuration,t=Number(e.replace("ms",""));o.style.transitionDelay=Math.round(t/10)+"ms",i.style.transitionDuration=e,y([i],"visible")}},onShow:function(){i&&(i.style.transitionDuration="0ms")},onHide:function(){i&&y([i],"hidden")}}}};var $={clientX:0,clientY:0},q=[];function z(e){var t=e.clientX,n=e.clientY;$={clientX:t,clientY:n}}var J={name:"followCursor",defaultValue:!1,fn:function(e){var t=e.reference,n=w(e.props.triggerTarget||t),r=!1,o=!1,i=!0,a=e.props;function s(){return"initial"===e.props.followCursor&&e.state.isVisible}function u(){n.addEventListener("mousemove",f)}function c(){n.removeEventListener("mousemove",f)}function p(){r=!0,e.setProps({getReferenceClientRect:null}),r=!1}function f(n){var r=!n.target||t.contains(n.target),o=e.props.followCursor,i=n.clientX,a=n.clientY,s=t.getBoundingClientRect(),u=i-s.left,c=a-s.top;!r&&e.props.interactive||e.setProps({getReferenceClientRect:function(){var e=t.getBoundingClientRect(),n=i,r=a;"initial"===o&&(n=e.left+u,r=e.top+c);var s="horizontal"===o?e.top:r,p="vertical"===o?e.right:n,f="horizontal"===o?e.bottom:r,l="vertical"===o?e.left:n;return{width:p-l,height:f-s,top:s,right:p,bottom:f,left:l}}})}function l(){e.props.followCursor&&(q.push({instance:e,doc:n}),function(e){e.addEventListener("mousemove",z)}(n))}function d(){0===(q=q.filter((function(t){return t.instance!==e}))).filter((function(e){return e.doc===n})).length&&function(e){e.removeEventListener("mousemove",z)}(n)}return{onCreate:l,onDestroy:d,onBeforeUpdate:function(){a=e.props},onAfterUpdate:function(t,n){var i=n.followCursor;r||void 0!==i&&a.followCursor!==i&&(d(),i?(l(),!e.state.isMounted||o||s()||u()):(c(),p()))},onMount:function(){e.props.followCursor&&!o&&(i&&(f($),i=!1),s()||u())},onTrigger:function(e,t){m(t)&&($={clientX:t.clientX,clientY:t.clientY}),o="focus"===t.type},onHidden:function(){e.props.followCursor&&(p(),c(),i=!0)}}}};var G={name:"inlinePositioning",defaultValue:!1,fn:function(e){var t,n=e.reference;var r=-1,o=!1,i=[],a={name:"tippyInlinePositioning",enabled:!0,phase:"afterWrite",fn:function(o){var a=o.state;e.props.inlinePositioning&&(-1!==i.indexOf(a.placement)&&(i=[]),t!==a.placement&&-1===i.indexOf(a.placement)&&(i.push(a.placement),e.setProps({getReferenceClientRect:function(){return function(e){return function(e,t,n,r){if(n.length<2||null===e)return t;if(2===n.length&&r>=0&&n[0].left>n[1].right)return n[r]||t;switch(e){case"top":case"bottom":var o=n[0],i=n[n.length-1],a="top"===e,s=o.top,u=i.bottom,c=a?o.left:i.left,p=a?o.right:i.right;return{top:s,bottom:u,left:c,right:p,width:p-c,height:u-s};case"left":case"right":var f=Math.min.apply(Math,n.map((function(e){return e.left}))),l=Math.max.apply(Math,n.map((function(e){return e.right}))),d=n.filter((function(t){return"left"===e?t.left===f:t.right===l})),v=d[0].top,m=d[d.length-1].bottom;return{top:v,bottom:m,left:f,right:l,width:l-f,height:m-v};default:return t}}(p(e),n.getBoundingClientRect(),f(n.getClientRects()),r)}(a.placement)}})),t=a.placement)}};function s(){var t;o||(t=function(e,t){var n;return{popperOptions:Object.assign({},e.popperOptions,{modifiers:[].concat(((null==(n=e.popperOptions)?void 0:n.modifiers)||[]).filter((function(e){return e.name!==t.name})),[t])})}}(e.props,a),o=!0,e.setProps(t),o=!1)}return{onCreate:s,onAfterUpdate:s,onTrigger:function(t,n){if(m(n)){var o=f(e.reference.getClientRects()),i=o.find((function(e){return e.left-2<=n.clientX&&e.right+2>=n.clientX&&e.top-2<=n.clientY&&e.bottom+2>=n.clientY})),a=o.indexOf(i);r=a>-1?a:r}},onHidden:function(){r=-1}}}};var K={name:"sticky",defaultValue:!1,fn:function(e){var t=e.reference,n=e.popper;function r(t){return!0===e.props.sticky||e.props.sticky===t}var o=null,i=null;function a(){var s=r("reference")?(e.popperInstance?e.popperInstance.state.elements.reference:t).getBoundingClientRect():null,u=r("popper")?n.getBoundingClientRect():null;(s&&Q(o,s)||u&&Q(i,u))&&e.popperInstance&&e.popperInstance.update(),o=s,i=u,e.state.isMounted&&requestAnimationFrame(a)}return{onMount:function(){e.props.sticky&&a()}}}};function Q(e,t){return!e||!t||(e.top!==t.top||e.right!==t.right||e.bottom!==t.bottom||e.left!==t.left)}return F.setDefaultProps({plugins:[Y,J,G,K],render:N}),F.createSingleton=function(e,t){var n;void 0===t&&(t={});var r,o=e,i=[],a=[],c=t.overrides,p=[],f=!1;function l(){a=o.map((function(e){return u(e.props.triggerTarget||e.reference)})).reduce((function(e,t){return e.concat(t)}),[])}function v(){i=o.map((function(e){return e.reference}))}function m(e){o.forEach((function(t){e?t.enable():t.disable()}))}function g(e){return o.map((function(t){var n=t.setProps;return t.setProps=function(o){n(o),t.reference===r&&e.setProps(o)},function(){t.setProps=n}}))}function h(e,t){var n=a.indexOf(t);if(t!==r){r=t;var s=(c||[]).concat("content").reduce((function(e,t){return e[t]=o[n].props[t],e}),{});e.setProps(Object.assign({},s,{getReferenceClientRect:"function"==typeof s.getReferenceClientRect?s.getReferenceClientRect:function(){var e;return null==(e=i[n])?void 0:e.getBoundingClientRect()}}))}}m(!1),v(),l();var b={fn:function(){return{onDestroy:function(){m(!0)},onHidden:function(){r=null},onClickOutside:function(e){e.props.showOnCreate&&!f&&(f=!0,r=null)},onShow:function(e){e.props.showOnCreate&&!f&&(f=!0,h(e,i[0]))},onTrigger:function(e,t){h(e,t.currentTarget)}}}},y=F(d(),Object.assign({},s(t,["overrides"]),{plugins:[b].concat(t.plugins||[]),triggerTarget:a,popperOptions:Object.assign({},t.popperOptions,{modifiers:[].concat((null==(n=t.popperOptions)?void 0:n.modifiers)||[],[W])})})),w=y.show;y.show=function(e){if(w(),!r&&null==e)return h(y,i[0]);if(!r||null!=e){if("number"==typeof e)return i[e]&&h(y,i[e]);if(o.indexOf(e)>=0){var t=e.reference;return h(y,t)}return i.indexOf(e)>=0?h(y,e):void 0}},y.showNext=function(){var e=i[0];if(!r)return y.show(0);var t=i.indexOf(r);y.show(i[t+1]||e)},y.showPrevious=function(){var e=i[i.length-1];if(!r)return y.show(e);var t=i.indexOf(r),n=i[t-1]||e;y.show(n)};var E=y.setProps;return y.setProps=function(e){c=e.overrides||c,E(e)},y.setInstances=function(e){m(!0),p.forEach((function(e){return e()})),o=e,m(!1),v(),l(),p=g(y),y.setProps({triggerTarget:a})},p=g(y),y},F.delegate=function(e,n){var r=[],o=[],i=!1,a=n.target,c=s(n,["target"]),p=Object.assign({},c,{trigger:"manual",touch:!1}),f=Object.assign({touch:R.touch},c,{showOnCreate:!0}),l=F(e,p);function d(e){if(e.target&&!i){var t=e.target.closest(a);if(t){var r=t.getAttribute("data-tippy-trigger")||n.trigger||R.trigger;if(!t._tippy&&!("touchstart"===e.type&&"boolean"==typeof f.touch||"touchstart"!==e.type&&r.indexOf(X[e.type])<0)){var s=F(t,f);s&&(o=o.concat(s))}}}}function v(e,t,n,o){void 0===o&&(o=!1),e.addEventListener(t,n,o),r.push({node:e,eventType:t,handler:n,options:o})}return u(l).forEach((function(e){var n=e.destroy,a=e.enable,s=e.disable;e.destroy=function(e){void 0===e&&(e=!0),e&&o.forEach((function(e){e.destroy()})),o=[],r.forEach((function(e){var t=e.node,n=e.eventType,r=e.handler,o=e.options;t.removeEventListener(n,r,o)})),r=[],n()},e.enable=function(){a(),o.forEach((function(e){return e.enable()})),i=!1},e.disable=function(){s(),o.forEach((function(e){return e.disable()})),i=!0},function(e){var n=e.reference;v(n,"touchstart",d,t),v(n,"mouseover",d),v(n,"focusin",d),v(n,"click",d)}(e)})),l},F.hideAll=function(e){var t=void 0===e?{}:e,n=t.exclude,r=t.duration;U.forEach((function(e){var t=!1;if(n&&(t=g(n)?e.reference===n:e.popper===n.popper),!t){var o=e.props.duration;e.setProps({duration:r}),e.hide(),e.state.isDestroyed||e.setProps({duration:o})}}))},F.roundArrow='<svg width="16" height="6" xmlns="http://www.w3.org/2000/svg"><path d="M0 6s1.796-.013 4.67-3.615C5.851.9 6.93.006 8 0c1.07-.006 2.148.887 3.343 2.385C14.233 6.005 16 6 16 6H0z"></svg>',F})); + diff --git a/site_libs/quarto-listing/list.min.js b/site_libs/quarto-listing/list.min.js new file mode 100644 index 00000000..81318815 --- /dev/null +++ b/site_libs/quarto-listing/list.min.js @@ -0,0 +1,2 @@ +var List;List=function(){var t={"./src/add-async.js":function(t){t.exports=function(t){return function e(r,n,s){var i=r.splice(0,50);s=(s=s||[]).concat(t.add(i)),r.length>0?setTimeout((function(){e(r,n,s)}),1):(t.update(),n(s))}}},"./src/filter.js":function(t){t.exports=function(t){return t.handlers.filterStart=t.handlers.filterStart||[],t.handlers.filterComplete=t.handlers.filterComplete||[],function(e){if(t.trigger("filterStart"),t.i=1,t.reset.filter(),void 0===e)t.filtered=!1;else{t.filtered=!0;for(var r=t.items,n=0,s=r.length;n<s;n++){var i=r[n];e(i)?i.filtered=!0:i.filtered=!1}}return t.update(),t.trigger("filterComplete"),t.visibleItems}}},"./src/fuzzy-search.js":function(t,e,r){r("./src/utils/classes.js");var n=r("./src/utils/events.js"),s=r("./src/utils/extend.js"),i=r("./src/utils/to-string.js"),a=r("./src/utils/get-by-class.js"),o=r("./src/utils/fuzzy.js");t.exports=function(t,e){e=s({location:0,distance:100,threshold:.4,multiSearch:!0,searchClass:"fuzzy-search"},e=e||{});var r={search:function(n,s){for(var i=e.multiSearch?n.replace(/ +$/,"").split(/ +/):[n],a=0,o=t.items.length;a<o;a++)r.item(t.items[a],s,i)},item:function(t,e,n){for(var s=!0,i=0;i<n.length;i++){for(var a=!1,o=0,l=e.length;o<l;o++)r.values(t.values(),e[o],n[i])&&(a=!0);a||(s=!1)}t.found=s},values:function(t,r,n){if(t.hasOwnProperty(r)){var s=i(t[r]).toLowerCase();if(o(s,n,e))return!0}return!1}};return n.bind(a(t.listContainer,e.searchClass),"keyup",t.utils.events.debounce((function(e){var n=e.target||e.srcElement;t.search(n.value,r.search)}),t.searchDelay)),function(e,n){t.search(e,n,r.search)}}},"./src/index.js":function(t,e,r){var n=r("./node_modules/string-natural-compare/natural-compare.js"),s=r("./src/utils/get-by-class.js"),i=r("./src/utils/extend.js"),a=r("./src/utils/index-of.js"),o=r("./src/utils/events.js"),l=r("./src/utils/to-string.js"),u=r("./src/utils/classes.js"),c=r("./src/utils/get-attribute.js"),f=r("./src/utils/to-array.js");t.exports=function(t,e,h){var d,v=this,g=r("./src/item.js")(v),m=r("./src/add-async.js")(v),p=r("./src/pagination.js")(v);d={start:function(){v.listClass="list",v.searchClass="search",v.sortClass="sort",v.page=1e4,v.i=1,v.items=[],v.visibleItems=[],v.matchingItems=[],v.searched=!1,v.filtered=!1,v.searchColumns=void 0,v.searchDelay=0,v.handlers={updated:[]},v.valueNames=[],v.utils={getByClass:s,extend:i,indexOf:a,events:o,toString:l,naturalSort:n,classes:u,getAttribute:c,toArray:f},v.utils.extend(v,e),v.listContainer="string"==typeof t?document.getElementById(t):t,v.listContainer&&(v.list=s(v.listContainer,v.listClass,!0),v.parse=r("./src/parse.js")(v),v.templater=r("./src/templater.js")(v),v.search=r("./src/search.js")(v),v.filter=r("./src/filter.js")(v),v.sort=r("./src/sort.js")(v),v.fuzzySearch=r("./src/fuzzy-search.js")(v,e.fuzzySearch),this.handlers(),this.items(),this.pagination(),v.update())},handlers:function(){for(var t in v.handlers)v[t]&&v.handlers.hasOwnProperty(t)&&v.on(t,v[t])},items:function(){v.parse(v.list),void 0!==h&&v.add(h)},pagination:function(){if(void 0!==e.pagination){!0===e.pagination&&(e.pagination=[{}]),void 0===e.pagination[0]&&(e.pagination=[e.pagination]);for(var t=0,r=e.pagination.length;t<r;t++)p(e.pagination[t])}}},this.reIndex=function(){v.items=[],v.visibleItems=[],v.matchingItems=[],v.searched=!1,v.filtered=!1,v.parse(v.list)},this.toJSON=function(){for(var t=[],e=0,r=v.items.length;e<r;e++)t.push(v.items[e].values());return t},this.add=function(t,e){if(0!==t.length){if(!e){var r=[],n=!1;void 0===t[0]&&(t=[t]);for(var s=0,i=t.length;s<i;s++){var a;n=v.items.length>v.page,a=new g(t[s],void 0,n),v.items.push(a),r.push(a)}return v.update(),r}m(t.slice(0),e)}},this.show=function(t,e){return this.i=t,this.page=e,v.update(),v},this.remove=function(t,e,r){for(var n=0,s=0,i=v.items.length;s<i;s++)v.items[s].values()[t]==e&&(v.templater.remove(v.items[s],r),v.items.splice(s,1),i--,s--,n++);return v.update(),n},this.get=function(t,e){for(var r=[],n=0,s=v.items.length;n<s;n++){var i=v.items[n];i.values()[t]==e&&r.push(i)}return r},this.size=function(){return v.items.length},this.clear=function(){return v.templater.clear(),v.items=[],v},this.on=function(t,e){return v.handlers[t].push(e),v},this.off=function(t,e){var r=v.handlers[t],n=a(r,e);return n>-1&&r.splice(n,1),v},this.trigger=function(t){for(var e=v.handlers[t].length;e--;)v.handlers[t][e](v);return v},this.reset={filter:function(){for(var t=v.items,e=t.length;e--;)t[e].filtered=!1;return v},search:function(){for(var t=v.items,e=t.length;e--;)t[e].found=!1;return v}},this.update=function(){var t=v.items,e=t.length;v.visibleItems=[],v.matchingItems=[],v.templater.clear();for(var r=0;r<e;r++)t[r].matching()&&v.matchingItems.length+1>=v.i&&v.visibleItems.length<v.page?(t[r].show(),v.visibleItems.push(t[r]),v.matchingItems.push(t[r])):t[r].matching()?(v.matchingItems.push(t[r]),t[r].hide()):t[r].hide();return v.trigger("updated"),v},d.start()}},"./src/item.js":function(t){t.exports=function(t){return function(e,r,n){var s=this;this._values={},this.found=!1,this.filtered=!1;this.values=function(e,r){if(void 0===e)return s._values;for(var n in e)s._values[n]=e[n];!0!==r&&t.templater.set(s,s.values())},this.show=function(){t.templater.show(s)},this.hide=function(){t.templater.hide(s)},this.matching=function(){return t.filtered&&t.searched&&s.found&&s.filtered||t.filtered&&!t.searched&&s.filtered||!t.filtered&&t.searched&&s.found||!t.filtered&&!t.searched},this.visible=function(){return!(!s.elm||s.elm.parentNode!=t.list)},function(e,r,n){if(void 0===r)n?s.values(e,n):s.values(e);else{s.elm=r;var i=t.templater.get(s,e);s.values(i)}}(e,r,n)}}},"./src/pagination.js":function(t,e,r){var n=r("./src/utils/classes.js"),s=r("./src/utils/events.js"),i=r("./src/index.js");t.exports=function(t){var e=!1,r=function(r,s){if(t.page<1)return t.listContainer.style.display="none",void(e=!0);e&&(t.listContainer.style.display="block");var i,o=t.matchingItems.length,l=t.i,u=t.page,c=Math.ceil(o/u),f=Math.ceil(l/u),h=s.innerWindow||2,d=s.left||s.outerWindow||0,v=s.right||s.outerWindow||0;v=c-v,r.clear();for(var g=1;g<=c;g++){var m=f===g?"active":"";a.number(g,d,v,f,h)?(i=r.add({page:g,dotted:!1})[0],m&&n(i.elm).add(m),i.elm.firstChild.setAttribute("data-i",g),i.elm.firstChild.setAttribute("data-page",u)):a.dotted(r,g,d,v,f,h,r.size())&&(i=r.add({page:"...",dotted:!0})[0],n(i.elm).add("disabled"))}},a={number:function(t,e,r,n,s){return this.left(t,e)||this.right(t,r)||this.innerWindow(t,n,s)},left:function(t,e){return t<=e},right:function(t,e){return t>e},innerWindow:function(t,e,r){return t>=e-r&&t<=e+r},dotted:function(t,e,r,n,s,i,a){return this.dottedLeft(t,e,r,n,s,i)||this.dottedRight(t,e,r,n,s,i,a)},dottedLeft:function(t,e,r,n,s,i){return e==r+1&&!this.innerWindow(e,s,i)&&!this.right(e,n)},dottedRight:function(t,e,r,n,s,i,a){return!t.items[a-1].values().dotted&&(e==n&&!this.innerWindow(e,s,i)&&!this.right(e,n))}};return function(e){var n=new i(t.listContainer.id,{listClass:e.paginationClass||"pagination",item:e.item||"<li><a class='page' href='#'></a></li>",valueNames:["page","dotted"],searchClass:"pagination-search-that-is-not-supposed-to-exist",sortClass:"pagination-sort-that-is-not-supposed-to-exist"});s.bind(n.listContainer,"click",(function(e){var r=e.target||e.srcElement,n=t.utils.getAttribute(r,"data-page"),s=t.utils.getAttribute(r,"data-i");s&&t.show((s-1)*n+1,n)})),t.on("updated",(function(){r(n,e)})),r(n,e)}}},"./src/parse.js":function(t,e,r){t.exports=function(t){var e=r("./src/item.js")(t),n=function(r,n){for(var s=0,i=r.length;s<i;s++)t.items.push(new e(n,r[s]))},s=function e(r,s){var i=r.splice(0,50);n(i,s),r.length>0?setTimeout((function(){e(r,s)}),1):(t.update(),t.trigger("parseComplete"))};return t.handlers.parseComplete=t.handlers.parseComplete||[],function(){var e=function(t){for(var e=t.childNodes,r=[],n=0,s=e.length;n<s;n++)void 0===e[n].data&&r.push(e[n]);return r}(t.list),r=t.valueNames;t.indexAsync?s(e,r):n(e,r)}}},"./src/search.js":function(t){t.exports=function(t){var e,r,n,s={resetList:function(){t.i=1,t.templater.clear(),n=void 0},setOptions:function(t){2==t.length&&t[1]instanceof Array?e=t[1]:2==t.length&&"function"==typeof t[1]?(e=void 0,n=t[1]):3==t.length?(e=t[1],n=t[2]):e=void 0},setColumns:function(){0!==t.items.length&&void 0===e&&(e=void 0===t.searchColumns?s.toArray(t.items[0].values()):t.searchColumns)},setSearchString:function(e){e=(e=t.utils.toString(e).toLowerCase()).replace(/[-[\]{}()*+?.,\\^$|#]/g,"\\$&"),r=e},toArray:function(t){var e=[];for(var r in t)e.push(r);return e}},i=function(){for(var n,s=[],i=r;null!==(n=i.match(/"([^"]+)"/));)s.push(n[1]),i=i.substring(0,n.index)+i.substring(n.index+n[0].length);(i=i.trim()).length&&(s=s.concat(i.split(/\s+/)));for(var a=0,o=t.items.length;a<o;a++){var l=t.items[a];if(l.found=!1,s.length){for(var u=0,c=s.length;u<c;u++){for(var f=!1,h=0,d=e.length;h<d;h++){var v=l.values(),g=e[h];if(v.hasOwnProperty(g)&&void 0!==v[g]&&null!==v[g])if(-1!==("string"!=typeof v[g]?v[g].toString():v[g]).toLowerCase().indexOf(s[u])){f=!0;break}}if(!f)break}l.found=f}}},a=function(){t.reset.search(),t.searched=!1},o=function(o){return t.trigger("searchStart"),s.resetList(),s.setSearchString(o),s.setOptions(arguments),s.setColumns(),""===r?a():(t.searched=!0,n?n(r,e):i()),t.update(),t.trigger("searchComplete"),t.visibleItems};return t.handlers.searchStart=t.handlers.searchStart||[],t.handlers.searchComplete=t.handlers.searchComplete||[],t.utils.events.bind(t.utils.getByClass(t.listContainer,t.searchClass),"keyup",t.utils.events.debounce((function(e){var r=e.target||e.srcElement;""===r.value&&!t.searched||o(r.value)}),t.searchDelay)),t.utils.events.bind(t.utils.getByClass(t.listContainer,t.searchClass),"input",(function(t){""===(t.target||t.srcElement).value&&o("")})),o}},"./src/sort.js":function(t){t.exports=function(t){var e={els:void 0,clear:function(){for(var r=0,n=e.els.length;r<n;r++)t.utils.classes(e.els[r]).remove("asc"),t.utils.classes(e.els[r]).remove("desc")},getOrder:function(e){var r=t.utils.getAttribute(e,"data-order");return"asc"==r||"desc"==r?r:t.utils.classes(e).has("desc")?"asc":t.utils.classes(e).has("asc")?"desc":"asc"},getInSensitive:function(e,r){var n=t.utils.getAttribute(e,"data-insensitive");r.insensitive="false"!==n},setOrder:function(r){for(var n=0,s=e.els.length;n<s;n++){var i=e.els[n];if(t.utils.getAttribute(i,"data-sort")===r.valueName){var a=t.utils.getAttribute(i,"data-order");"asc"==a||"desc"==a?a==r.order&&t.utils.classes(i).add(r.order):t.utils.classes(i).add(r.order)}}}},r=function(){t.trigger("sortStart");var r={},n=arguments[0].currentTarget||arguments[0].srcElement||void 0;n?(r.valueName=t.utils.getAttribute(n,"data-sort"),e.getInSensitive(n,r),r.order=e.getOrder(n)):((r=arguments[1]||r).valueName=arguments[0],r.order=r.order||"asc",r.insensitive=void 0===r.insensitive||r.insensitive),e.clear(),e.setOrder(r);var s,i=r.sortFunction||t.sortFunction||null,a="desc"===r.order?-1:1;s=i?function(t,e){return i(t,e,r)*a}:function(e,n){var s=t.utils.naturalSort;return s.alphabet=t.alphabet||r.alphabet||void 0,!s.alphabet&&r.insensitive&&(s=t.utils.naturalSort.caseInsensitive),s(e.values()[r.valueName],n.values()[r.valueName])*a},t.items.sort(s),t.update(),t.trigger("sortComplete")};return t.handlers.sortStart=t.handlers.sortStart||[],t.handlers.sortComplete=t.handlers.sortComplete||[],e.els=t.utils.getByClass(t.listContainer,t.sortClass),t.utils.events.bind(e.els,"click",r),t.on("searchStart",e.clear),t.on("filterStart",e.clear),r}},"./src/templater.js":function(t){var e=function(t){var e,r=this,n=function(e,r){var n=e.cloneNode(!0);n.removeAttribute("id");for(var s=0,i=r.length;s<i;s++){var a=void 0,o=r[s];if(o.data)for(var l=0,u=o.data.length;l<u;l++)n.setAttribute("data-"+o.data[l],"");else o.attr&&o.name?(a=t.utils.getByClass(n,o.name,!0))&&a.setAttribute(o.attr,""):(a=t.utils.getByClass(n,o,!0))&&(a.innerHTML="")}return n},s=function(){for(var e=t.list.childNodes,r=0,n=e.length;r<n;r++)if(void 0===e[r].data)return e[r].cloneNode(!0)},i=function(t){if("string"==typeof t){if(/<tr[\s>]/g.exec(t)){var e=document.createElement("tbody");return e.innerHTML=t,e.firstElementChild}if(-1!==t.indexOf("<")){var r=document.createElement("div");return r.innerHTML=t,r.firstElementChild}}},a=function(e,r,n){var s=void 0,i=function(e){for(var r=0,n=t.valueNames.length;r<n;r++){var s=t.valueNames[r];if(s.data){for(var i=s.data,a=0,o=i.length;a<o;a++)if(i[a]===e)return{data:e}}else{if(s.attr&&s.name&&s.name==e)return s;if(s===e)return e}}}(r);i&&(i.data?e.elm.setAttribute("data-"+i.data,n):i.attr&&i.name?(s=t.utils.getByClass(e.elm,i.name,!0))&&s.setAttribute(i.attr,n):(s=t.utils.getByClass(e.elm,i,!0))&&(s.innerHTML=n))};this.get=function(e,n){r.create(e);for(var s={},i=0,a=n.length;i<a;i++){var o=void 0,l=n[i];if(l.data)for(var u=0,c=l.data.length;u<c;u++)s[l.data[u]]=t.utils.getAttribute(e.elm,"data-"+l.data[u]);else l.attr&&l.name?(o=t.utils.getByClass(e.elm,l.name,!0),s[l.name]=o?t.utils.getAttribute(o,l.attr):""):(o=t.utils.getByClass(e.elm,l,!0),s[l]=o?o.innerHTML:"")}return s},this.set=function(t,e){if(!r.create(t))for(var n in e)e.hasOwnProperty(n)&&a(t,n,e[n])},this.create=function(t){return void 0===t.elm&&(t.elm=e(t.values()),r.set(t,t.values()),!0)},this.remove=function(e){e.elm.parentNode===t.list&&t.list.removeChild(e.elm)},this.show=function(e){r.create(e),t.list.appendChild(e.elm)},this.hide=function(e){void 0!==e.elm&&e.elm.parentNode===t.list&&t.list.removeChild(e.elm)},this.clear=function(){if(t.list.hasChildNodes())for(;t.list.childNodes.length>=1;)t.list.removeChild(t.list.firstChild)},function(){var r;if("function"!=typeof t.item){if(!(r="string"==typeof t.item?-1===t.item.indexOf("<")?document.getElementById(t.item):i(t.item):s()))throw new Error("The list needs to have at least one item on init otherwise you'll have to add a template.");r=n(r,t.valueNames),e=function(){return r.cloneNode(!0)}}else e=function(e){var r=t.item(e);return i(r)}}()};t.exports=function(t){return new e(t)}},"./src/utils/classes.js":function(t,e,r){var n=r("./src/utils/index-of.js"),s=/\s+/;Object.prototype.toString;function i(t){if(!t||!t.nodeType)throw new Error("A DOM element reference is required");this.el=t,this.list=t.classList}t.exports=function(t){return new i(t)},i.prototype.add=function(t){if(this.list)return this.list.add(t),this;var e=this.array();return~n(e,t)||e.push(t),this.el.className=e.join(" "),this},i.prototype.remove=function(t){if(this.list)return this.list.remove(t),this;var e=this.array(),r=n(e,t);return~r&&e.splice(r,1),this.el.className=e.join(" "),this},i.prototype.toggle=function(t,e){return this.list?(void 0!==e?e!==this.list.toggle(t,e)&&this.list.toggle(t):this.list.toggle(t),this):(void 0!==e?e?this.add(t):this.remove(t):this.has(t)?this.remove(t):this.add(t),this)},i.prototype.array=function(){var t=(this.el.getAttribute("class")||"").replace(/^\s+|\s+$/g,"").split(s);return""===t[0]&&t.shift(),t},i.prototype.has=i.prototype.contains=function(t){return this.list?this.list.contains(t):!!~n(this.array(),t)}},"./src/utils/events.js":function(t,e,r){var n=window.addEventListener?"addEventListener":"attachEvent",s=window.removeEventListener?"removeEventListener":"detachEvent",i="addEventListener"!==n?"on":"",a=r("./src/utils/to-array.js");e.bind=function(t,e,r,s){for(var o=0,l=(t=a(t)).length;o<l;o++)t[o][n](i+e,r,s||!1)},e.unbind=function(t,e,r,n){for(var o=0,l=(t=a(t)).length;o<l;o++)t[o][s](i+e,r,n||!1)},e.debounce=function(t,e,r){var n;return e?function(){var s=this,i=arguments,a=function(){n=null,r||t.apply(s,i)},o=r&&!n;clearTimeout(n),n=setTimeout(a,e),o&&t.apply(s,i)}:t}},"./src/utils/extend.js":function(t){t.exports=function(t){for(var e,r=Array.prototype.slice.call(arguments,1),n=0;e=r[n];n++)if(e)for(var s in e)t[s]=e[s];return t}},"./src/utils/fuzzy.js":function(t){t.exports=function(t,e,r){var n=r.location||0,s=r.distance||100,i=r.threshold||.4;if(e===t)return!0;if(e.length>32)return!1;var a=n,o=function(){var t,r={};for(t=0;t<e.length;t++)r[e.charAt(t)]=0;for(t=0;t<e.length;t++)r[e.charAt(t)]|=1<<e.length-t-1;return r}();function l(t,r){var n=t/e.length,i=Math.abs(a-r);return s?n+i/s:i?1:n}var u=i,c=t.indexOf(e,a);-1!=c&&(u=Math.min(l(0,c),u),-1!=(c=t.lastIndexOf(e,a+e.length))&&(u=Math.min(l(0,c),u)));var f,h,d=1<<e.length-1;c=-1;for(var v,g=e.length+t.length,m=0;m<e.length;m++){for(f=0,h=g;f<h;)l(m,a+h)<=u?f=h:g=h,h=Math.floor((g-f)/2+f);g=h;var p=Math.max(1,a-h+1),y=Math.min(a+h,t.length)+e.length,C=Array(y+2);C[y+1]=(1<<m)-1;for(var b=y;b>=p;b--){var j=o[t.charAt(b-1)];if(C[b]=0===m?(C[b+1]<<1|1)&j:(C[b+1]<<1|1)&j|(v[b+1]|v[b])<<1|1|v[b+1],C[b]&d){var x=l(m,b-1);if(x<=u){if(u=x,!((c=b-1)>a))break;p=Math.max(1,2*a-c)}}}if(l(m+1,a)>u)break;v=C}return!(c<0)}},"./src/utils/get-attribute.js":function(t){t.exports=function(t,e){var r=t.getAttribute&&t.getAttribute(e)||null;if(!r)for(var n=t.attributes,s=n.length,i=0;i<s;i++)void 0!==n[i]&&n[i].nodeName===e&&(r=n[i].nodeValue);return r}},"./src/utils/get-by-class.js":function(t){t.exports=function(t,e,r,n){return(n=n||{}).test&&n.getElementsByClassName||!n.test&&document.getElementsByClassName?function(t,e,r){return r?t.getElementsByClassName(e)[0]:t.getElementsByClassName(e)}(t,e,r):n.test&&n.querySelector||!n.test&&document.querySelector?function(t,e,r){return e="."+e,r?t.querySelector(e):t.querySelectorAll(e)}(t,e,r):function(t,e,r){for(var n=[],s=t.getElementsByTagName("*"),i=s.length,a=new RegExp("(^|\\s)"+e+"(\\s|$)"),o=0,l=0;o<i;o++)if(a.test(s[o].className)){if(r)return s[o];n[l]=s[o],l++}return n}(t,e,r)}},"./src/utils/index-of.js":function(t){var e=[].indexOf;t.exports=function(t,r){if(e)return t.indexOf(r);for(var n=0,s=t.length;n<s;++n)if(t[n]===r)return n;return-1}},"./src/utils/to-array.js":function(t){t.exports=function(t){if(void 0===t)return[];if(null===t)return[null];if(t===window)return[window];if("string"==typeof t)return[t];if(function(t){return"[object Array]"===Object.prototype.toString.call(t)}(t))return t;if("number"!=typeof t.length)return[t];if("function"==typeof t&&t instanceof Function)return[t];for(var e=[],r=0,n=t.length;r<n;r++)(Object.prototype.hasOwnProperty.call(t,r)||r in t)&&e.push(t[r]);return e.length?e:[]}},"./src/utils/to-string.js":function(t){t.exports=function(t){return t=(t=null===(t=void 0===t?"":t)?"":t).toString()}},"./node_modules/string-natural-compare/natural-compare.js":function(t){"use strict";var e,r,n=0;function s(t){return t>=48&&t<=57}function i(t,e){for(var i=(t+="").length,a=(e+="").length,o=0,l=0;o<i&&l<a;){var u=t.charCodeAt(o),c=e.charCodeAt(l);if(s(u)){if(!s(c))return u-c;for(var f=o,h=l;48===u&&++f<i;)u=t.charCodeAt(f);for(;48===c&&++h<a;)c=e.charCodeAt(h);for(var d=f,v=h;d<i&&s(t.charCodeAt(d));)++d;for(;v<a&&s(e.charCodeAt(v));)++v;var g=d-f-v+h;if(g)return g;for(;f<d;)if(g=t.charCodeAt(f++)-e.charCodeAt(h++))return g;o=d,l=v}else{if(u!==c)return u<n&&c<n&&-1!==r[u]&&-1!==r[c]?r[u]-r[c]:u-c;++o,++l}}return o>=i&&l<a&&i>=a?-1:l>=a&&o<i&&a>=i?1:i-a}i.caseInsensitive=i.i=function(t,e){return i((""+t).toLowerCase(),(""+e).toLowerCase())},Object.defineProperties(i,{alphabet:{get:function(){return e},set:function(t){r=[];var s=0;if(e=t)for(;s<e.length;s++)r[e.charCodeAt(s)]=s;for(n=r.length,s=0;s<n;s++)void 0===r[s]&&(r[s]=-1)}}}),t.exports=i}},e={};return function r(n){if(e[n])return e[n].exports;var s=e[n]={exports:{}};return t[n](s,s.exports,r),s.exports}("./src/index.js")}(); +//# sourceMappingURL=list.min.js.map \ No newline at end of file diff --git a/site_libs/quarto-listing/quarto-listing.js b/site_libs/quarto-listing/quarto-listing.js new file mode 100644 index 00000000..88d209a9 --- /dev/null +++ b/site_libs/quarto-listing/quarto-listing.js @@ -0,0 +1,243 @@ +const kProgressiveAttr = "data-src"; +let categoriesLoaded = false; + +window.quartoListingCategory = (category) => { + if (categoriesLoaded) { + activateCategory(category); + setCategoryHash(category); + } +}; + +window["quarto-listing-loaded"] = () => { + // Process any existing hash + const hash = getHash(); + + if (hash) { + // If there is a category, switch to that + if (hash.category) { + activateCategory(hash.category); + } + // Paginate a specific listing + const listingIds = Object.keys(window["quarto-listings"]); + for (const listingId of listingIds) { + const page = hash[getListingPageKey(listingId)]; + if (page) { + showPage(listingId, page); + } + } + } + + const listingIds = Object.keys(window["quarto-listings"]); + for (const listingId of listingIds) { + // The actual list + const list = window["quarto-listings"][listingId]; + + // Update the handlers for pagination events + refreshPaginationHandlers(listingId); + + // Render any visible items that need it + renderVisibleProgressiveImages(list); + + // Whenever the list is updated, we also need to + // attach handlers to the new pagination elements + // and refresh any newly visible items. + list.on("updated", function () { + renderVisibleProgressiveImages(list); + setTimeout(() => refreshPaginationHandlers(listingId)); + + // Show or hide the no matching message + toggleNoMatchingMessage(list); + }); + } +}; + +window.document.addEventListener("DOMContentLoaded", function (_event) { + // Attach click handlers to categories + const categoryEls = window.document.querySelectorAll( + ".quarto-listing-category .category" + ); + + for (const categoryEl of categoryEls) { + const category = categoryEl.getAttribute("data-category"); + categoryEl.onclick = () => { + activateCategory(category); + setCategoryHash(category); + }; + } + + // Attach a click handler to the category title + // (there should be only one, but since it is a class name, handle N) + const categoryTitleEls = window.document.querySelectorAll( + ".quarto-listing-category-title" + ); + for (const categoryTitleEl of categoryTitleEls) { + categoryTitleEl.onclick = () => { + activateCategory(""); + setCategoryHash(""); + }; + } + + categoriesLoaded = true; +}); + +function toggleNoMatchingMessage(list) { + const selector = `#${list.listContainer.id} .listing-no-matching`; + const noMatchingEl = window.document.querySelector(selector); + if (noMatchingEl) { + if (list.visibleItems.length === 0) { + noMatchingEl.classList.remove("d-none"); + } else { + if (!noMatchingEl.classList.contains("d-none")) { + noMatchingEl.classList.add("d-none"); + } + } + } +} + +function setCategoryHash(category) { + setHash({ category }); +} + +function setPageHash(listingId, page) { + const currentHash = getHash() || {}; + currentHash[getListingPageKey(listingId)] = page; + setHash(currentHash); +} + +function getListingPageKey(listingId) { + return `${listingId}-page`; +} + +function refreshPaginationHandlers(listingId) { + const listingEl = window.document.getElementById(listingId); + const paginationEls = listingEl.querySelectorAll( + ".pagination li.page-item:not(.disabled) .page.page-link" + ); + for (const paginationEl of paginationEls) { + paginationEl.onclick = (sender) => { + setPageHash(listingId, sender.target.getAttribute("data-i")); + showPage(listingId, sender.target.getAttribute("data-i")); + return false; + }; + } +} + +function renderVisibleProgressiveImages(list) { + // Run through the visible items and render any progressive images + for (const item of list.visibleItems) { + const itemEl = item.elm; + if (itemEl) { + const progressiveImgs = itemEl.querySelectorAll( + `img[${kProgressiveAttr}]` + ); + for (const progressiveImg of progressiveImgs) { + const srcValue = progressiveImg.getAttribute(kProgressiveAttr); + if (srcValue) { + progressiveImg.setAttribute("src", srcValue); + } + progressiveImg.removeAttribute(kProgressiveAttr); + } + } + } +} + +function getHash() { + // Hashes are of the form + // #name:value|name1:value1|name2:value2 + const currentUrl = new URL(window.location); + const hashRaw = currentUrl.hash ? currentUrl.hash.slice(1) : undefined; + return parseHash(hashRaw); +} + +const kAnd = "&"; +const kEquals = "="; + +function parseHash(hash) { + if (!hash) { + return undefined; + } + const hasValuesStrs = hash.split(kAnd); + const hashValues = hasValuesStrs + .map((hashValueStr) => { + const vals = hashValueStr.split(kEquals); + if (vals.length === 2) { + return { name: vals[0], value: vals[1] }; + } else { + return undefined; + } + }) + .filter((value) => { + return value !== undefined; + }); + + const hashObj = {}; + hashValues.forEach((hashValue) => { + hashObj[hashValue.name] = decodeURIComponent(hashValue.value); + }); + return hashObj; +} + +function makeHash(obj) { + return Object.keys(obj) + .map((key) => { + return `${key}${kEquals}${obj[key]}`; + }) + .join(kAnd); +} + +function setHash(obj) { + const hash = makeHash(obj); + window.history.pushState(null, null, `#${hash}`); +} + +function showPage(listingId, page) { + const list = window["quarto-listings"][listingId]; + if (list) { + list.show((page - 1) * list.page + 1, list.page); + } +} + +function activateCategory(category) { + // Deactivate existing categories + const activeEls = window.document.querySelectorAll( + ".quarto-listing-category .category.active" + ); + for (const activeEl of activeEls) { + activeEl.classList.remove("active"); + } + + // Activate this category + const categoryEl = window.document.querySelector( + `.quarto-listing-category .category[data-category='${category}'` + ); + if (categoryEl) { + categoryEl.classList.add("active"); + } + + // Filter the listings to this category + filterListingCategory(category); +} + +function filterListingCategory(category) { + const listingIds = Object.keys(window["quarto-listings"]); + for (const listingId of listingIds) { + const list = window["quarto-listings"][listingId]; + if (list) { + if (category === "") { + // resets the filter + list.filter(); + } else { + // filter to this category + list.filter(function (item) { + const itemValues = item.values(); + if (itemValues.categories !== null) { + const categories = itemValues.categories.split(","); + return categories.includes(category); + } else { + return false; + } + }); + } + } + } +} diff --git a/site_libs/quarto-nav/headroom.min.js b/site_libs/quarto-nav/headroom.min.js new file mode 100644 index 00000000..b08f1dff --- /dev/null +++ b/site_libs/quarto-nav/headroom.min.js @@ -0,0 +1,7 @@ +/*! + * headroom.js v0.12.0 - Give your page some headroom. Hide your header until you need it + * Copyright (c) 2020 Nick Williams - http://wicky.nillia.ms/headroom.js + * License: MIT + */ + +!function(t,n){"object"==typeof exports&&"undefined"!=typeof module?module.exports=n():"function"==typeof define&&define.amd?define(n):(t=t||self).Headroom=n()}(this,function(){"use strict";function t(){return"undefined"!=typeof window}function d(t){return function(t){return t&&t.document&&function(t){return 9===t.nodeType}(t.document)}(t)?function(t){var n=t.document,o=n.body,s=n.documentElement;return{scrollHeight:function(){return Math.max(o.scrollHeight,s.scrollHeight,o.offsetHeight,s.offsetHeight,o.clientHeight,s.clientHeight)},height:function(){return t.innerHeight||s.clientHeight||o.clientHeight},scrollY:function(){return void 0!==t.pageYOffset?t.pageYOffset:(s||o.parentNode||o).scrollTop}}}(t):function(t){return{scrollHeight:function(){return Math.max(t.scrollHeight,t.offsetHeight,t.clientHeight)},height:function(){return Math.max(t.offsetHeight,t.clientHeight)},scrollY:function(){return t.scrollTop}}}(t)}function n(t,s,e){var n,o=function(){var n=!1;try{var t={get passive(){n=!0}};window.addEventListener("test",t,t),window.removeEventListener("test",t,t)}catch(t){n=!1}return n}(),i=!1,r=d(t),l=r.scrollY(),a={};function c(){var t=Math.round(r.scrollY()),n=r.height(),o=r.scrollHeight();a.scrollY=t,a.lastScrollY=l,a.direction=l<t?"down":"up",a.distance=Math.abs(t-l),a.isOutOfBounds=t<0||o<t+n,a.top=t<=s.offset[a.direction],a.bottom=o<=t+n,a.toleranceExceeded=a.distance>s.tolerance[a.direction],e(a),l=t,i=!1}function h(){i||(i=!0,n=requestAnimationFrame(c))}var u=!!o&&{passive:!0,capture:!1};return t.addEventListener("scroll",h,u),c(),{destroy:function(){cancelAnimationFrame(n),t.removeEventListener("scroll",h,u)}}}function o(t){return t===Object(t)?t:{down:t,up:t}}function s(t,n){n=n||{},Object.assign(this,s.options,n),this.classes=Object.assign({},s.options.classes,n.classes),this.elem=t,this.tolerance=o(this.tolerance),this.offset=o(this.offset),this.initialised=!1,this.frozen=!1}return s.prototype={constructor:s,init:function(){return s.cutsTheMustard&&!this.initialised&&(this.addClass("initial"),this.initialised=!0,setTimeout(function(t){t.scrollTracker=n(t.scroller,{offset:t.offset,tolerance:t.tolerance},t.update.bind(t))},100,this)),this},destroy:function(){this.initialised=!1,Object.keys(this.classes).forEach(this.removeClass,this),this.scrollTracker.destroy()},unpin:function(){!this.hasClass("pinned")&&this.hasClass("unpinned")||(this.addClass("unpinned"),this.removeClass("pinned"),this.onUnpin&&this.onUnpin.call(this))},pin:function(){this.hasClass("unpinned")&&(this.addClass("pinned"),this.removeClass("unpinned"),this.onPin&&this.onPin.call(this))},freeze:function(){this.frozen=!0,this.addClass("frozen")},unfreeze:function(){this.frozen=!1,this.removeClass("frozen")},top:function(){this.hasClass("top")||(this.addClass("top"),this.removeClass("notTop"),this.onTop&&this.onTop.call(this))},notTop:function(){this.hasClass("notTop")||(this.addClass("notTop"),this.removeClass("top"),this.onNotTop&&this.onNotTop.call(this))},bottom:function(){this.hasClass("bottom")||(this.addClass("bottom"),this.removeClass("notBottom"),this.onBottom&&this.onBottom.call(this))},notBottom:function(){this.hasClass("notBottom")||(this.addClass("notBottom"),this.removeClass("bottom"),this.onNotBottom&&this.onNotBottom.call(this))},shouldUnpin:function(t){return"down"===t.direction&&!t.top&&t.toleranceExceeded},shouldPin:function(t){return"up"===t.direction&&t.toleranceExceeded||t.top},addClass:function(t){this.elem.classList.add.apply(this.elem.classList,this.classes[t].split(" "))},removeClass:function(t){this.elem.classList.remove.apply(this.elem.classList,this.classes[t].split(" "))},hasClass:function(t){return this.classes[t].split(" ").every(function(t){return this.classList.contains(t)},this.elem)},update:function(t){t.isOutOfBounds||!0!==this.frozen&&(t.top?this.top():this.notTop(),t.bottom?this.bottom():this.notBottom(),this.shouldUnpin(t)?this.unpin():this.shouldPin(t)&&this.pin())}},s.options={tolerance:{up:0,down:0},offset:0,scroller:t()?window:null,classes:{frozen:"headroom--frozen",pinned:"headroom--pinned",unpinned:"headroom--unpinned",top:"headroom--top",notTop:"headroom--not-top",bottom:"headroom--bottom",notBottom:"headroom--not-bottom",initial:"headroom"}},s.cutsTheMustard=!!(t()&&function(){}.bind&&"classList"in document.documentElement&&Object.assign&&Object.keys&&requestAnimationFrame),s}); diff --git a/site_libs/quarto-nav/quarto-nav.js b/site_libs/quarto-nav/quarto-nav.js new file mode 100644 index 00000000..3b21201f --- /dev/null +++ b/site_libs/quarto-nav/quarto-nav.js @@ -0,0 +1,277 @@ +const headroomChanged = new CustomEvent("quarto-hrChanged", { + detail: {}, + bubbles: true, + cancelable: false, + composed: false, +}); + +window.document.addEventListener("DOMContentLoaded", function () { + let init = false; + + // Manage the back to top button, if one is present. + let lastScrollTop = window.pageYOffset || document.documentElement.scrollTop; + const scrollDownBuffer = 5; + const scrollUpBuffer = 35; + const btn = document.getElementById("quarto-back-to-top"); + const hideBackToTop = () => { + btn.style.display = "none"; + }; + const showBackToTop = () => { + btn.style.display = "inline-block"; + }; + if (btn) { + window.document.addEventListener( + "scroll", + function () { + const currentScrollTop = + window.pageYOffset || document.documentElement.scrollTop; + + // Shows and hides the button 'intelligently' as the user scrolls + if (currentScrollTop - scrollDownBuffer > lastScrollTop) { + hideBackToTop(); + lastScrollTop = currentScrollTop <= 0 ? 0 : currentScrollTop; + } else if (currentScrollTop < lastScrollTop - scrollUpBuffer) { + showBackToTop(); + lastScrollTop = currentScrollTop <= 0 ? 0 : currentScrollTop; + } + + // Show the button at the bottom, hides it at the top + if (currentScrollTop <= 0) { + hideBackToTop(); + } else if ( + window.innerHeight + currentScrollTop >= + document.body.offsetHeight + ) { + showBackToTop(); + } + }, + false + ); + } + + function throttle(func, wait) { + var timeout; + return function () { + const context = this; + const args = arguments; + const later = function () { + clearTimeout(timeout); + timeout = null; + func.apply(context, args); + }; + + if (!timeout) { + timeout = setTimeout(later, wait); + } + }; + } + + function headerOffset() { + // Set an offset if there is are fixed top navbar + const headerEl = window.document.querySelector("header.fixed-top"); + if (headerEl) { + return headerEl.clientHeight; + } else { + return 0; + } + } + + function footerOffset() { + const footerEl = window.document.querySelector("footer.footer"); + if (footerEl) { + return footerEl.clientHeight; + } else { + return 0; + } + } + + function updateDocumentOffsetWithoutAnimation() { + updateDocumentOffset(false); + } + + function updateDocumentOffset(animated) { + // set body offset + const topOffset = headerOffset(); + const bodyOffset = topOffset + footerOffset(); + const bodyEl = window.document.body; + bodyEl.setAttribute("data-bs-offset", topOffset); + bodyEl.style.paddingTop = topOffset + "px"; + + // deal with sidebar offsets + const sidebars = window.document.querySelectorAll( + ".sidebar, .headroom-target" + ); + sidebars.forEach((sidebar) => { + if (!animated) { + sidebar.classList.add("notransition"); + // Remove the no transition class after the animation has time to complete + setTimeout(function () { + sidebar.classList.remove("notransition"); + }, 201); + } + + if (window.Headroom && sidebar.classList.contains("sidebar-unpinned")) { + sidebar.style.top = "0"; + sidebar.style.maxHeight = "100vh"; + } else { + sidebar.style.top = topOffset + "px"; + sidebar.style.maxHeight = "calc(100vh - " + topOffset + "px)"; + } + }); + + // allow space for footer + const mainContainer = window.document.querySelector(".quarto-container"); + if (mainContainer) { + mainContainer.style.minHeight = "calc(100vh - " + bodyOffset + "px)"; + } + + // link offset + let linkStyle = window.document.querySelector("#quarto-target-style"); + if (!linkStyle) { + linkStyle = window.document.createElement("style"); + linkStyle.setAttribute("id", "quarto-target-style"); + window.document.head.appendChild(linkStyle); + } + while (linkStyle.firstChild) { + linkStyle.removeChild(linkStyle.firstChild); + } + if (topOffset > 0) { + linkStyle.appendChild( + window.document.createTextNode(` + section:target::before { + content: ""; + display: block; + height: ${topOffset}px; + margin: -${topOffset}px 0 0; + }`) + ); + } + if (init) { + window.dispatchEvent(headroomChanged); + } + init = true; + } + + // initialize headroom + var header = window.document.querySelector("#quarto-header"); + if (header && window.Headroom) { + const headroom = new window.Headroom(header, { + tolerance: 5, + onPin: function () { + const sidebars = window.document.querySelectorAll( + ".sidebar, .headroom-target" + ); + sidebars.forEach((sidebar) => { + sidebar.classList.remove("sidebar-unpinned"); + }); + updateDocumentOffset(); + }, + onUnpin: function () { + const sidebars = window.document.querySelectorAll( + ".sidebar, .headroom-target" + ); + sidebars.forEach((sidebar) => { + sidebar.classList.add("sidebar-unpinned"); + }); + updateDocumentOffset(); + }, + }); + headroom.init(); + + let frozen = false; + window.quartoToggleHeadroom = function () { + if (frozen) { + headroom.unfreeze(); + frozen = false; + } else { + headroom.freeze(); + frozen = true; + } + }; + } + + window.addEventListener( + "hashchange", + function (e) { + if ( + getComputedStyle(document.documentElement).scrollBehavior !== "smooth" + ) { + window.scrollTo(0, window.pageYOffset - headerOffset()); + } + }, + false + ); + + // Observe size changed for the header + const headerEl = window.document.querySelector("header.fixed-top"); + if (headerEl && window.ResizeObserver) { + const observer = new window.ResizeObserver( + updateDocumentOffsetWithoutAnimation + ); + observer.observe(headerEl, { + attributes: true, + childList: true, + characterData: true, + }); + } else { + window.addEventListener( + "resize", + throttle(updateDocumentOffsetWithoutAnimation, 50) + ); + } + setTimeout(updateDocumentOffsetWithoutAnimation, 250); + + // fixup index.html links if we aren't on the filesystem + if (window.location.protocol !== "file:") { + const links = window.document.querySelectorAll("a"); + for (let i = 0; i < links.length; i++) { + if (links[i].href) { + links[i].href = links[i].href.replace(/\/index\.html/, "/"); + } + } + + // Fixup any sharing links that require urls + // Append url to any sharing urls + const sharingLinks = window.document.querySelectorAll( + "a.sidebar-tools-main-item" + ); + for (let i = 0; i < sharingLinks.length; i++) { + const sharingLink = sharingLinks[i]; + const href = sharingLink.getAttribute("href"); + if (href) { + sharingLink.setAttribute( + "href", + href.replace("|url|", window.location.href) + ); + } + } + + // Scroll the active navigation item into view, if necessary + const navSidebar = window.document.querySelector("nav#quarto-sidebar"); + if (navSidebar) { + // Find the active item + const activeItem = navSidebar.querySelector("li.sidebar-item a.active"); + if (activeItem) { + // Wait for the scroll height and height to resolve by observing size changes on the + // nav element that is scrollable + const resizeObserver = new ResizeObserver((_entries) => { + // The bottom of the element + const elBottom = activeItem.offsetTop; + const viewBottom = navSidebar.scrollTop + navSidebar.clientHeight; + + // The element height and scroll height are the same, then we are still loading + if (viewBottom !== navSidebar.scrollHeight) { + // Determine if the item isn't visible and scroll to it + if (elBottom >= viewBottom) { + navSidebar.scrollTop = elBottom; + } + + // stop observing now since we've completed the scroll + resizeObserver.unobserve(navSidebar); + } + }); + resizeObserver.observe(navSidebar); + } + } + } +}); diff --git a/site_libs/quarto-search/autocomplete.umd.js b/site_libs/quarto-search/autocomplete.umd.js new file mode 100644 index 00000000..619c57cc --- /dev/null +++ b/site_libs/quarto-search/autocomplete.umd.js @@ -0,0 +1,3 @@ +/*! @algolia/autocomplete-js 1.7.3 | MIT License | Ā© Algolia, Inc. and contributors | https://github.com/algolia/autocomplete */ +!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self)["@algolia/autocomplete-js"]={})}(this,(function(e){"use strict";function t(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function n(e){for(var n=1;n<arguments.length;n++){var r=null!=arguments[n]?arguments[n]:{};n%2?t(Object(r),!0).forEach((function(t){o(e,t,r[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(r)):t(Object(r)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(r,t))}))}return e}function r(e){return r="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},r(e)}function o(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function i(){return i=Object.assign||function(e){for(var t=1;t<arguments.length;t++){var n=arguments[t];for(var r in n)Object.prototype.hasOwnProperty.call(n,r)&&(e[r]=n[r])}return e},i.apply(this,arguments)}function u(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},i=Object.keys(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}function a(e,t){return function(e){if(Array.isArray(e))return e}(e)||function(e,t){var n=null==e?null:"undefined"!=typeof Symbol&&e[Symbol.iterator]||e["@@iterator"];if(null==n)return;var r,o,i=[],u=!0,a=!1;try{for(n=n.call(e);!(u=(r=n.next()).done)&&(i.push(r.value),!t||i.length!==t);u=!0);}catch(e){a=!0,o=e}finally{try{u||null==n.return||n.return()}finally{if(a)throw o}}return i}(e,t)||l(e,t)||function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function c(e){return function(e){if(Array.isArray(e))return s(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||l(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function l(e,t){if(e){if("string"==typeof e)return s(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?s(e,t):void 0}}function s(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n<t;n++)r[n]=e[n];return r}function p(e){return{current:e}}function f(e,t){var n=void 0;return function(){for(var r=arguments.length,o=new Array(r),i=0;i<r;i++)o[i]=arguments[i];n&&clearTimeout(n),n=setTimeout((function(){return e.apply(void 0,o)}),t)}}function d(e){return e.reduce((function(e,t){return e.concat(t)}),[])}var m=0;function v(){return"autocomplete-".concat(m++)}function h(e,t){return t.reduce((function(e,t){return e&&e[t]}),e)}function g(e){return 0===e.collections.length?0:e.collections.reduce((function(e,t){return e+t.items.length}),0)}var y=function(){},b="1.7.3",O=[{segment:"autocomplete-core",version:b}];function _(e,t){var n=t;return{then:function(t,r){return _(e.then(j(t,n,e),j(r,n,e)),n)},catch:function(t){return _(e.catch(j(t,n,e)),n)},finally:function(t){return t&&n.onCancelList.push(t),_(e.finally(j(t&&function(){return n.onCancelList=[],t()},n,e)),n)},cancel:function(){n.isCanceled=!0;var e=n.onCancelList;n.onCancelList=[],e.forEach((function(e){e()}))},isCanceled:function(){return!0===n.isCanceled}}}function P(e){return _(e,{isCanceled:!1,onCancelList:[]})}function j(e,t,n){return e?function(n){return t.isCanceled?n:e(n)}:n}function w(e,t,n,r){if(!n)return null;if(e<0&&(null===t||null!==r&&0===t))return n+e;var o=(null===t?-1:t)+e;return o<=-1||o>=n?null===r?null:0:o}function S(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function I(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function E(e,t){var n=[];return Promise.resolve(e(t)).then((function(e){return Promise.all(e.filter((function(e){return Boolean(e)})).map((function(e){if(e.sourceId,n.includes(e.sourceId))throw new Error("[Autocomplete] The `sourceId` ".concat(JSON.stringify(e.sourceId)," is not unique."));n.push(e.sourceId);var t=function(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?S(Object(n),!0).forEach((function(t){I(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):S(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}({getItemInputValue:function(e){return e.state.query},getItemUrl:function(){},onSelect:function(e){(0,e.setIsOpen)(!1)},onActive:y},e);return Promise.resolve(t)})))}))}function A(e){var t=function(e){var t=e.collections.map((function(e){return e.items.length})).reduce((function(e,t,n){var r=(e[n-1]||0)+t;return e.push(r),e}),[]).reduce((function(t,n){return n<=e.activeItemId?t+1:t}),0);return e.collections[t]}(e);if(!t)return null;var n=t.items[function(e){for(var t=e.state,n=e.collection,r=!1,o=0,i=0;!1===r;){var u=t.collections[o];if(u===n){r=!0;break}i+=u.items.length,o++}return t.activeItemId-i}({state:e,collection:t})],r=t.source;return{item:n,itemInputValue:r.getItemInputValue({item:n,state:e}),itemUrl:r.getItemUrl({item:n,state:e}),source:r}}var C=/((gt|sm)-|galaxy nexus)|samsung[- ]/i;function D(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function k(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?D(Object(n),!0).forEach((function(t){x(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):D(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function x(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function N(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function q(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function R(e,t,n){var r,o=t.initialState;return{getState:function(){return o},dispatch:function(r,i){var u=function(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?N(Object(n),!0).forEach((function(t){q(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):N(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}({},o);o=e(o,{type:r,props:t,payload:i}),n({state:o,prevState:u})},pendingRequests:(r=[],{add:function(e){return r.push(e),e.finally((function(){r=r.filter((function(t){return t!==e}))}))},cancelAll:function(){r.forEach((function(e){return e.cancel()}))},isEmpty:function(){return 0===r.length}})}}function T(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function L(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?T(Object(n),!0).forEach((function(t){B(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):T(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function B(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function F(e){return function(e){if(Array.isArray(e))return M(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,t){if(!e)return;if("string"==typeof e)return M(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return M(e,t)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function M(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n<t;n++)r[n]=e[n];return r}function U(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function H(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?U(Object(n),!0).forEach((function(t){V(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):U(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function V(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function W(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function Q(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?W(Object(n),!0).forEach((function(t){$(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):W(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function $(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function z(e){return function(e){if(Array.isArray(e))return G(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,t){if(!e)return;if("string"==typeof e)return G(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return G(e,t)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function G(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n<t;n++)r[n]=e[n];return r}function K(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function J(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?K(Object(n),!0).forEach((function(t){Y(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):K(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function Y(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function X(e){return Boolean(e.execute)}function Z(e,t){return n=e,Boolean(null==n?void 0:n.execute)?J(J({},e),{},{requests:e.queries.map((function(n){return{query:n,sourceId:t,transformResponse:e.transformResponse}}))}):{items:e,sourceId:t};var n}function ee(e){var t=e.reduce((function(e,t){if(!X(t))return e.push(t),e;var n=t.searchClient,r=t.execute,o=t.requesterId,i=t.requests,u=e.find((function(e){return X(t)&&X(e)&&e.searchClient===n&&Boolean(o)&&e.requesterId===o}));if(u){var a;(a=u.items).push.apply(a,z(i))}else{var c={execute:r,requesterId:o,items:i,searchClient:n};e.push(c)}return e}),[]).map((function(e){if(!X(e))return Promise.resolve(e);var t=e,n=t.execute,r=t.items;return n({searchClient:t.searchClient,requests:r})}));return Promise.all(t).then((function(e){return d(e)}))}function te(e,t){return t.map((function(t){var n=e.filter((function(e){return e.sourceId===t.sourceId})),r=n.map((function(e){return e.items})),o=n[0].transformResponse,i=o?o(function(e){var t=e.map((function(e){var t;return k(k({},e),{},{hits:null===(t=e.hits)||void 0===t?void 0:t.map((function(t){return k(k({},t),{},{__autocomplete_indexName:e.index,__autocomplete_queryID:e.queryID})}))})}));return{results:t,hits:t.map((function(e){return e.hits})).filter(Boolean),facetHits:t.map((function(e){var t;return null===(t=e.facetHits)||void 0===t?void 0:t.map((function(e){return{label:e.value,count:e.count,_highlightResult:{label:{value:e.highlighted}}}}))})).filter(Boolean)}}(r)):r;return i.every(Boolean),'The `getItems` function from source "'.concat(t.sourceId,'" must return an array of items but returned ').concat(JSON.stringify(void 0),".\n\nDid you forget to return items?\n\nSee: https://www.algolia.com/doc/ui-libraries/autocomplete/core-concepts/sources/#param-getitems"),{source:t,items:i}}))}var ne=["event","nextState","props","query","refresh","store"];function re(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function oe(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?re(Object(n),!0).forEach((function(t){ie(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):re(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function ie(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function ue(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},i=Object.keys(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var ae,ce,le,se=null,pe=(ae=-1,ce=-1,le=void 0,function(e){var t=++ae;return Promise.resolve(e).then((function(e){return le&&t<ce?le:(ce=t,le=e,e)}))});function fe(e){var t=e.event,n=e.nextState,r=void 0===n?{}:n,o=e.props,i=e.query,u=e.refresh,a=e.store,c=ue(e,ne);se&&o.environment.clearTimeout(se);var l=c.setCollections,s=c.setIsOpen,p=c.setQuery,f=c.setActiveItemId,m=c.setStatus;if(p(i),f(o.defaultActiveItemId),!i&&!1===o.openOnFocus){var v,h=a.getState().collections.map((function(e){return oe(oe({},e),{},{items:[]})}));m("idle"),l(h),s(null!==(v=r.isOpen)&&void 0!==v?v:o.shouldPanelOpen({state:a.getState()}));var g=P(pe(h).then((function(){return Promise.resolve()})));return a.pendingRequests.add(g)}m("loading"),se=o.environment.setTimeout((function(){m("stalled")}),o.stallThreshold);var y=P(pe(o.getSources(oe({query:i,refresh:u,state:a.getState()},c)).then((function(e){return Promise.all(e.map((function(e){return Promise.resolve(e.getItems(oe({query:i,refresh:u,state:a.getState()},c))).then((function(t){return Z(t,e.sourceId)}))}))).then(ee).then((function(t){return te(t,e)})).then((function(e){return function(e){var t=e.collections,n=e.props,r=e.state,o=t.reduce((function(e,t){return Q(Q({},e),{},$({},t.source.sourceId,Q(Q({},t.source),{},{getItems:function(){return d(t.items)}})))}),{});return d(n.reshape({sources:Object.values(o),sourcesBySourceId:o,state:r})).filter(Boolean).map((function(e){return{source:e,items:e.getItems()}}))}({collections:e,props:o,state:a.getState()})}))})))).then((function(e){var n;m("idle"),l(e);var p=o.shouldPanelOpen({state:a.getState()});s(null!==(n=r.isOpen)&&void 0!==n?n:o.openOnFocus&&!i&&p||p);var f=A(a.getState());if(null!==a.getState().activeItemId&&f){var d=f.item,v=f.itemInputValue,h=f.itemUrl,g=f.source;g.onActive(oe({event:t,item:d,itemInputValue:v,itemUrl:h,refresh:u,source:g,state:a.getState()},c))}})).finally((function(){m("idle"),se&&o.environment.clearTimeout(se)}));return a.pendingRequests.add(y)}var de=["event","props","refresh","store"];function me(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function ve(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?me(Object(n),!0).forEach((function(t){he(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):me(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function he(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function ge(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},i=Object.keys(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}var ye=["props","refresh","store"],be=["inputElement","formElement","panelElement"],Oe=["inputElement"],_e=["inputElement","maxLength"],Pe=["item","source"];function je(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function we(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?je(Object(n),!0).forEach((function(t){Se(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):je(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function Se(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function Ie(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},i=Object.keys(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}function Ee(e){var t=e.props,n=e.refresh,r=e.store,o=Ie(e,ye);return{getEnvironmentProps:function(e){var n=e.inputElement,o=e.formElement,i=e.panelElement;function u(e){!r.getState().isOpen&&r.pendingRequests.isEmpty()||e.target===n||!1===[o,i].some((function(t){return n=t,r=e.target,n===r||n.contains(r);var n,r}))&&(r.dispatch("blur",null),t.debug||r.pendingRequests.cancelAll())}return we({onTouchStart:u,onMouseDown:u,onTouchMove:function(e){!1!==r.getState().isOpen&&n===t.environment.document.activeElement&&e.target!==n&&n.blur()}},Ie(e,be))},getRootProps:function(e){return we({role:"combobox","aria-expanded":r.getState().isOpen,"aria-haspopup":"listbox","aria-owns":r.getState().isOpen?"".concat(t.id,"-list"):void 0,"aria-labelledby":"".concat(t.id,"-label")},e)},getFormProps:function(e){return e.inputElement,we({action:"",noValidate:!0,role:"search",onSubmit:function(i){var u;i.preventDefault(),t.onSubmit(we({event:i,refresh:n,state:r.getState()},o)),r.dispatch("submit",null),null===(u=e.inputElement)||void 0===u||u.blur()},onReset:function(i){var u;i.preventDefault(),t.onReset(we({event:i,refresh:n,state:r.getState()},o)),r.dispatch("reset",null),null===(u=e.inputElement)||void 0===u||u.focus()}},Ie(e,Oe))},getLabelProps:function(e){return we({htmlFor:"".concat(t.id,"-input"),id:"".concat(t.id,"-label")},e)},getInputProps:function(e){var i;function u(e){(t.openOnFocus||Boolean(r.getState().query))&&fe(we({event:e,props:t,query:r.getState().completion||r.getState().query,refresh:n,store:r},o)),r.dispatch("focus",null)}var a=e||{};a.inputElement;var c=a.maxLength,l=void 0===c?512:c,s=Ie(a,_e),p=A(r.getState()),f=function(e){return Boolean(e&&e.match(C))}((null===(i=t.environment.navigator)||void 0===i?void 0:i.userAgent)||""),d=null!=p&&p.itemUrl&&!f?"go":"search";return we({"aria-autocomplete":"both","aria-activedescendant":r.getState().isOpen&&null!==r.getState().activeItemId?"".concat(t.id,"-item-").concat(r.getState().activeItemId):void 0,"aria-controls":r.getState().isOpen?"".concat(t.id,"-list"):void 0,"aria-labelledby":"".concat(t.id,"-label"),value:r.getState().completion||r.getState().query,id:"".concat(t.id,"-input"),autoComplete:"off",autoCorrect:"off",autoCapitalize:"off",enterKeyHint:d,spellCheck:"false",autoFocus:t.autoFocus,placeholder:t.placeholder,maxLength:l,type:"search",onChange:function(e){fe(we({event:e,props:t,query:e.currentTarget.value.slice(0,l),refresh:n,store:r},o))},onKeyDown:function(e){!function(e){var t=e.event,n=e.props,r=e.refresh,o=e.store,i=ge(e,de);if("ArrowUp"===t.key||"ArrowDown"===t.key){var u=function(){var e=n.environment.document.getElementById("".concat(n.id,"-item-").concat(o.getState().activeItemId));e&&(e.scrollIntoViewIfNeeded?e.scrollIntoViewIfNeeded(!1):e.scrollIntoView(!1))},a=function(){var e=A(o.getState());if(null!==o.getState().activeItemId&&e){var n=e.item,u=e.itemInputValue,a=e.itemUrl,c=e.source;c.onActive(ve({event:t,item:n,itemInputValue:u,itemUrl:a,refresh:r,source:c,state:o.getState()},i))}};t.preventDefault(),!1===o.getState().isOpen&&(n.openOnFocus||Boolean(o.getState().query))?fe(ve({event:t,props:n,query:o.getState().query,refresh:r,store:o},i)).then((function(){o.dispatch(t.key,{nextActiveItemId:n.defaultActiveItemId}),a(),setTimeout(u,0)})):(o.dispatch(t.key,{}),a(),u())}else if("Escape"===t.key)t.preventDefault(),o.dispatch(t.key,null),o.pendingRequests.cancelAll();else if("Tab"===t.key)o.dispatch("blur",null),o.pendingRequests.cancelAll();else if("Enter"===t.key){if(null===o.getState().activeItemId||o.getState().collections.every((function(e){return 0===e.items.length})))return void(n.debug||o.pendingRequests.cancelAll());t.preventDefault();var c=A(o.getState()),l=c.item,s=c.itemInputValue,p=c.itemUrl,f=c.source;if(t.metaKey||t.ctrlKey)void 0!==p&&(f.onSelect(ve({event:t,item:l,itemInputValue:s,itemUrl:p,refresh:r,source:f,state:o.getState()},i)),n.navigator.navigateNewTab({itemUrl:p,item:l,state:o.getState()}));else if(t.shiftKey)void 0!==p&&(f.onSelect(ve({event:t,item:l,itemInputValue:s,itemUrl:p,refresh:r,source:f,state:o.getState()},i)),n.navigator.navigateNewWindow({itemUrl:p,item:l,state:o.getState()}));else if(t.altKey);else{if(void 0!==p)return f.onSelect(ve({event:t,item:l,itemInputValue:s,itemUrl:p,refresh:r,source:f,state:o.getState()},i)),void n.navigator.navigate({itemUrl:p,item:l,state:o.getState()});fe(ve({event:t,nextState:{isOpen:!1},props:n,query:s,refresh:r,store:o},i)).then((function(){f.onSelect(ve({event:t,item:l,itemInputValue:s,itemUrl:p,refresh:r,source:f,state:o.getState()},i))}))}}}(we({event:e,props:t,refresh:n,store:r},o))},onFocus:u,onBlur:y,onClick:function(n){e.inputElement!==t.environment.document.activeElement||r.getState().isOpen||u(n)}},s)},getPanelProps:function(e){return we({onMouseDown:function(e){e.preventDefault()},onMouseLeave:function(){r.dispatch("mouseleave",null)}},e)},getListProps:function(e){return we({role:"listbox","aria-labelledby":"".concat(t.id,"-label"),id:"".concat(t.id,"-list")},e)},getItemProps:function(e){var i=e.item,u=e.source,a=Ie(e,Pe);return we({id:"".concat(t.id,"-item-").concat(i.__autocomplete_id),role:"option","aria-selected":r.getState().activeItemId===i.__autocomplete_id,onMouseMove:function(e){if(i.__autocomplete_id!==r.getState().activeItemId){r.dispatch("mousemove",i.__autocomplete_id);var t=A(r.getState());if(null!==r.getState().activeItemId&&t){var u=t.item,a=t.itemInputValue,c=t.itemUrl,l=t.source;l.onActive(we({event:e,item:u,itemInputValue:a,itemUrl:c,refresh:n,source:l,state:r.getState()},o))}}},onMouseDown:function(e){e.preventDefault()},onClick:function(e){var a=u.getItemInputValue({item:i,state:r.getState()}),c=u.getItemUrl({item:i,state:r.getState()});(c?Promise.resolve():fe(we({event:e,nextState:{isOpen:!1},props:t,query:a,refresh:n,store:r},o))).then((function(){u.onSelect(we({event:e,item:i,itemInputValue:a,itemUrl:c,refresh:n,source:u,state:r.getState()},o))}))}},a)}}}function Ae(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function Ce(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?Ae(Object(n),!0).forEach((function(t){De(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):Ae(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function De(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function ke(e){var t,n,r,o,i=e.plugins,u=e.options,a=null===(t=((null===(n=u.__autocomplete_metadata)||void 0===n?void 0:n.userAgents)||[])[0])||void 0===t?void 0:t.segment,c=a?De({},a,Object.keys((null===(r=u.__autocomplete_metadata)||void 0===r?void 0:r.options)||{})):{};return{plugins:i.map((function(e){return{name:e.name,options:Object.keys(e.__autocomplete_pluginOptions||[])}})),options:Ce({"autocomplete-core":Object.keys(u)},c),ua:O.concat((null===(o=u.__autocomplete_metadata)||void 0===o?void 0:o.userAgents)||[])}}function xe(e){var t,n=e.state;return!1===n.isOpen||null===n.activeItemId?null:(null===(t=A(n))||void 0===t?void 0:t.itemInputValue)||null}function Ne(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function qe(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?Ne(Object(n),!0).forEach((function(t){Re(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):Ne(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function Re(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}var Te=function(e,t){switch(t.type){case"setActiveItemId":case"mousemove":return qe(qe({},e),{},{activeItemId:t.payload});case"setQuery":return qe(qe({},e),{},{query:t.payload,completion:null});case"setCollections":return qe(qe({},e),{},{collections:t.payload});case"setIsOpen":return qe(qe({},e),{},{isOpen:t.payload});case"setStatus":return qe(qe({},e),{},{status:t.payload});case"setContext":return qe(qe({},e),{},{context:qe(qe({},e.context),t.payload)});case"ArrowDown":var n=qe(qe({},e),{},{activeItemId:t.payload.hasOwnProperty("nextActiveItemId")?t.payload.nextActiveItemId:w(1,e.activeItemId,g(e),t.props.defaultActiveItemId)});return qe(qe({},n),{},{completion:xe({state:n})});case"ArrowUp":var r=qe(qe({},e),{},{activeItemId:w(-1,e.activeItemId,g(e),t.props.defaultActiveItemId)});return qe(qe({},r),{},{completion:xe({state:r})});case"Escape":return e.isOpen?qe(qe({},e),{},{activeItemId:null,isOpen:!1,completion:null}):qe(qe({},e),{},{activeItemId:null,query:"",status:"idle",collections:[]});case"submit":return qe(qe({},e),{},{activeItemId:null,isOpen:!1,status:"idle"});case"reset":return qe(qe({},e),{},{activeItemId:!0===t.props.openOnFocus?t.props.defaultActiveItemId:null,status:"idle",query:""});case"focus":return qe(qe({},e),{},{activeItemId:t.props.defaultActiveItemId,isOpen:(t.props.openOnFocus||Boolean(e.query))&&t.props.shouldPanelOpen({state:e})});case"blur":return t.props.debug?e:qe(qe({},e),{},{isOpen:!1,activeItemId:null});case"mouseleave":return qe(qe({},e),{},{activeItemId:t.props.defaultActiveItemId});default:return"The reducer action ".concat(JSON.stringify(t.type)," is not supported."),e}};function Le(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function Be(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?Le(Object(n),!0).forEach((function(t){Fe(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):Le(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function Fe(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function Me(e){var t=[],n=function(e,t){var n,r="undefined"!=typeof window?window:{},o=e.plugins||[];return H(H({debug:!1,openOnFocus:!1,placeholder:"",autoFocus:!1,defaultActiveItemId:null,stallThreshold:300,environment:r,shouldPanelOpen:function(e){return g(e.state)>0},reshape:function(e){return e.sources}},e),{},{id:null!==(n=e.id)&&void 0!==n?n:v(),plugins:o,initialState:H({activeItemId:null,query:"",completion:null,collections:[],isOpen:!1,status:"idle",context:{}},e.initialState),onStateChange:function(t){var n;null===(n=e.onStateChange)||void 0===n||n.call(e,t),o.forEach((function(e){var n;return null===(n=e.onStateChange)||void 0===n?void 0:n.call(e,t)}))},onSubmit:function(t){var n;null===(n=e.onSubmit)||void 0===n||n.call(e,t),o.forEach((function(e){var n;return null===(n=e.onSubmit)||void 0===n?void 0:n.call(e,t)}))},onReset:function(t){var n;null===(n=e.onReset)||void 0===n||n.call(e,t),o.forEach((function(e){var n;return null===(n=e.onReset)||void 0===n?void 0:n.call(e,t)}))},getSources:function(n){return Promise.all([].concat(F(o.map((function(e){return e.getSources}))),[e.getSources]).filter(Boolean).map((function(e){return E(e,n)}))).then((function(e){return d(e)})).then((function(e){return e.map((function(e){return H(H({},e),{},{onSelect:function(n){e.onSelect(n),t.forEach((function(e){var t;return null===(t=e.onSelect)||void 0===t?void 0:t.call(e,n)}))},onActive:function(n){e.onActive(n),t.forEach((function(e){var t;return null===(t=e.onActive)||void 0===t?void 0:t.call(e,n)}))}})}))}))},navigator:H({navigate:function(e){var t=e.itemUrl;r.location.assign(t)},navigateNewTab:function(e){var t=e.itemUrl,n=r.open(t,"_blank","noopener");null==n||n.focus()},navigateNewWindow:function(e){var t=e.itemUrl;r.open(t,"_blank","noopener")}},e.navigator)})}(e,t),r=R(Te,n,(function(e){var t=e.prevState,r=e.state;n.onStateChange(Be({prevState:t,state:r,refresh:u},o))})),o=function(e){var t=e.store;return{setActiveItemId:function(e){t.dispatch("setActiveItemId",e)},setQuery:function(e){t.dispatch("setQuery",e)},setCollections:function(e){var n=0,r=e.map((function(e){return L(L({},e),{},{items:d(e.items).map((function(e){return L(L({},e),{},{__autocomplete_id:n++})}))})}));t.dispatch("setCollections",r)},setIsOpen:function(e){t.dispatch("setIsOpen",e)},setStatus:function(e){t.dispatch("setStatus",e)},setContext:function(e){t.dispatch("setContext",e)}}}({store:r}),i=Ee(Be({props:n,refresh:u,store:r},o));function u(){return fe(Be({event:new Event("input"),nextState:{isOpen:r.getState().isOpen},props:n,query:r.getState().query,refresh:u,store:r},o))}return n.plugins.forEach((function(e){var n;return null===(n=e.subscribe)||void 0===n?void 0:n.call(e,Be(Be({},o),{},{refresh:u,onSelect:function(e){t.push({onSelect:e})},onActive:function(e){t.push({onActive:e})}}))})),function(e){var t,n,r=e.metadata,o=e.environment;if(null===(t=o.navigator)||void 0===t||null===(n=t.userAgent)||void 0===n?void 0:n.includes("Algolia Crawler")){var i=o.document.createElement("meta"),u=o.document.querySelector("head");i.name="algolia:metadata",setTimeout((function(){i.content=JSON.stringify(r),u.appendChild(i)}),0)}}({metadata:ke({plugins:n.plugins,options:e}),environment:n.environment}),Be(Be({refresh:u},i),o)}var Ue=function(e,t,n,r){var o;t[0]=0;for(var i=1;i<t.length;i++){var u=t[i++],a=t[i]?(t[0]|=u?1:2,n[t[i++]]):t[++i];3===u?r[0]=a:4===u?r[1]=Object.assign(r[1]||{},a):5===u?(r[1]=r[1]||{})[t[++i]]=a:6===u?r[1][t[++i]]+=a+"":u?(o=e.apply(a,Ue(e,a,n,["",null])),r.push(o),a[0]?t[0]|=2:(t[i-2]=0,t[i]=o)):r.push(a)}return r},He=new Map;function Ve(e){var t=He.get(this);return t||(t=new Map,He.set(this,t)),(t=Ue(this,t.get(e)||(t.set(e,t=function(e){for(var t,n,r=1,o="",i="",u=[0],a=function(e){1===r&&(e||(o=o.replace(/^\s*\n\s*|\s*\n\s*$/g,"")))?u.push(0,e,o):3===r&&(e||o)?(u.push(3,e,o),r=2):2===r&&"..."===o&&e?u.push(4,e,0):2===r&&o&&!e?u.push(5,0,!0,o):r>=5&&((o||!e&&5===r)&&(u.push(r,0,o,n),r=6),e&&(u.push(r,e,0,n),r=6)),o=""},c=0;c<e.length;c++){c&&(1===r&&a(),a(c));for(var l=0;l<e[c].length;l++)t=e[c][l],1===r?"<"===t?(a(),u=[u],r=3):o+=t:4===r?"--"===o&&">"===t?(r=1,o=""):o=t+o[0]:i?t===i?i="":o+=t:'"'===t||"'"===t?i=t:">"===t?(a(),r=1):r&&("="===t?(r=5,n=o,o=""):"/"===t&&(r<5||">"===e[c][l+1])?(a(),3===r&&(u=u[0]),r=u,(u=u[0]).push(2,0,r),r=0):" "===t||"\t"===t||"\n"===t||"\r"===t?(a(),r=2):o+=t),3===r&&"!--"===o&&(r=4,u=u[0])}return a(),u}(e)),t),arguments,[])).length>1?t:t[0]}var We=function(e){var t=e.environment,n=t.document.createElementNS("http://www.w3.org/2000/svg","svg");n.setAttribute("class","aa-ClearIcon"),n.setAttribute("viewBox","0 0 24 24"),n.setAttribute("width","18"),n.setAttribute("height","18"),n.setAttribute("fill","currentColor");var r=t.document.createElementNS("http://www.w3.org/2000/svg","path");return r.setAttribute("d","M5.293 6.707l5.293 5.293-5.293 5.293c-0.391 0.391-0.391 1.024 0 1.414s1.024 0.391 1.414 0l5.293-5.293 5.293 5.293c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414l-5.293-5.293 5.293-5.293c0.391-0.391 0.391-1.024 0-1.414s-1.024-0.391-1.414 0l-5.293 5.293-5.293-5.293c-0.391-0.391-1.024-0.391-1.414 0s-0.391 1.024 0 1.414z"),n.appendChild(r),n};function Qe(e,t){if("string"==typeof t){var n=e.document.querySelector(t);return"The element ".concat(JSON.stringify(t)," is not in the document."),n}return t}function $e(){for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];return t.reduce((function(e,t){return Object.keys(t).forEach((function(n){var r=e[n],o=t[n];r!==o&&(e[n]=[r,o].filter(Boolean).join(" "))})),e}),{})}var ze=function(e){return e&&"object"===r(e)&&"[object Object]"===Object.prototype.toString.call(e)};function Ge(){for(var e=arguments.length,t=new Array(e),n=0;n<e;n++)t[n]=arguments[n];return t.reduce((function(e,t){return Object.keys(t).forEach((function(n){var r=e[n],o=t[n];Array.isArray(r)&&Array.isArray(o)?e[n]=r.concat.apply(r,c(o)):ze(r)&&ze(o)?e[n]=Ge(r,o):e[n]=o})),e}),{})}function Ke(e,t){return Object.entries(e).reduce((function(e,r){var i=a(r,2),u=i[0],c=i[1];return t({key:u,value:c})?n(n({},e),{},o({},u,c)):e}),{})}var Je=["ontouchstart","ontouchend","ontouchmove","ontouchcancel"];function Ye(e,t,n){e[t]=null===n?"":"number"!=typeof n?n:n+"px"}function Xe(e){this._listeners[e.type](e)}function Ze(e,t,n){var r,o,i=e[t];if("style"===t)if("string"==typeof n)e.style=n;else if(null===n)e.style="";else for(t in n)i&&n[t]===i[t]||Ye(e.style,t,n[t]);else"o"===t[0]&&"n"===t[1]?(r=t!==(t=t.replace(/Capture$/,"")),((o=t.toLowerCase())in e||Je.includes(o))&&(t=o),t=t.slice(2),e._listeners||(e._listeners={}),e._listeners[t]=n,n?i||e.addEventListener(t,Xe,r):e.removeEventListener(t,Xe,r)):"list"!==t&&"tagName"!==t&&"form"!==t&&"type"!==t&&"size"!==t&&"download"!==t&&"href"!==t&&t in e?e[t]=null==n?"":n:"function"!=typeof n&&"dangerouslySetInnerHTML"!==t&&(null==n||!1===n&&!/^ar/.test(t)?e.removeAttribute(t):e.setAttribute(t,n))}function et(e){return"onChange"===e?"onInput":e}function tt(e,t){for(var n in t)Ze(e,et(n),t[n])}function nt(e,t){for(var n in t)"o"===n[0]&&"n"===n[1]||Ze(e,et(n),t[n])}var rt=["children"];function ot(e){return function(t,n){var r=n.children,o=void 0===r?[]:r,i=u(n,rt),a=e.document.createElement(t);return tt(a,i),a.append.apply(a,c(o)),a}}var it=["autocompleteScopeApi","environment","classNames","getInputProps","getInputPropsCore","isDetached","state"],ut=function(e){var t=e.environment.document.createElementNS("http://www.w3.org/2000/svg","svg");return t.setAttribute("class","aa-LoadingIcon"),t.setAttribute("viewBox","0 0 100 100"),t.setAttribute("width","20"),t.setAttribute("height","20"),t.innerHTML='<circle\n cx="50"\n cy="50"\n fill="none"\n r="35"\n stroke="currentColor"\n stroke-dasharray="164.93361431346415 56.97787143782138"\n stroke-width="6"\n>\n <animateTransform\n attributeName="transform"\n type="rotate"\n repeatCount="indefinite"\n dur="1s"\n values="0 50 50;90 50 50;180 50 50;360 50 50"\n keyTimes="0;0.40;0.65;1"\n />\n</circle>',t},at=function(e){var t=e.environment,n=t.document.createElementNS("http://www.w3.org/2000/svg","svg");n.setAttribute("class","aa-SubmitIcon"),n.setAttribute("viewBox","0 0 24 24"),n.setAttribute("width","20"),n.setAttribute("height","20"),n.setAttribute("fill","currentColor");var r=t.document.createElementNS("http://www.w3.org/2000/svg","path");return r.setAttribute("d","M16.041 15.856c-0.034 0.026-0.067 0.055-0.099 0.087s-0.060 0.064-0.087 0.099c-1.258 1.213-2.969 1.958-4.855 1.958-1.933 0-3.682-0.782-4.95-2.050s-2.050-3.017-2.050-4.95 0.782-3.682 2.050-4.95 3.017-2.050 4.95-2.050 3.682 0.782 4.95 2.050 2.050 3.017 2.050 4.95c0 1.886-0.745 3.597-1.959 4.856zM21.707 20.293l-3.675-3.675c1.231-1.54 1.968-3.493 1.968-5.618 0-2.485-1.008-4.736-2.636-6.364s-3.879-2.636-6.364-2.636-4.736 1.008-6.364 2.636-2.636 3.879-2.636 6.364 1.008 4.736 2.636 6.364 3.879 2.636 6.364 2.636c2.125 0 4.078-0.737 5.618-1.968l3.675 3.675c0.391 0.391 1.024 0.391 1.414 0s0.391-1.024 0-1.414z"),n.appendChild(r),n};function ct(e){var t=e.autocomplete,r=e.autocompleteScopeApi,o=e.classNames,i=e.environment,a=e.isDetached,c=e.placeholder,l=void 0===c?"Search":c,s=e.propGetters,p=e.setIsModalOpen,f=e.state,d=e.translations,m=ot(i),v=s.getRootProps(n({state:f,props:t.getRootProps({})},r)),h=m("div",n({class:o.root},v)),g=m("div",{class:o.detachedContainer,onMouseDown:function(e){e.stopPropagation()}}),y=m("div",{class:o.detachedOverlay,children:[g],onMouseDown:function(){p(!1),t.setIsOpen(!1)}}),b=s.getLabelProps(n({state:f,props:t.getLabelProps({})},r)),O=m("button",{class:o.submitButton,type:"submit",title:d.submitButtonTitle,children:[at({environment:i})]}),_=m("label",n({class:o.label,children:[O]},b)),P=m("button",{class:o.clearButton,type:"reset",title:d.clearButtonTitle,children:[We({environment:i})]}),j=m("div",{class:o.loadingIndicator,children:[ut({environment:i})]}),w=function(e){var t=e.autocompleteScopeApi,r=e.environment;e.classNames;var o=e.getInputProps,i=e.getInputPropsCore,a=e.isDetached,c=e.state,l=u(e,it),s=ot(r)("input",l),p=o(n({state:c,props:i({inputElement:s}),inputElement:s},t));return tt(s,n(n({},p),{},{onKeyDown:function(e){a&&"Tab"===e.key||p.onKeyDown(e)}})),s}({class:o.input,environment:i,state:f,getInputProps:s.getInputProps,getInputPropsCore:t.getInputProps,autocompleteScopeApi:r,isDetached:a}),S=m("div",{class:o.inputWrapperPrefix,children:[_,j]}),I=m("div",{class:o.inputWrapperSuffix,children:[P]}),E=m("div",{class:o.inputWrapper,children:[w]}),A=s.getFormProps(n({state:f,props:t.getFormProps({inputElement:w})},r)),C=m("form",n({class:o.form,children:[S,E,I]},A)),D=s.getPanelProps(n({state:f,props:t.getPanelProps({})},r)),k=m("div",n({class:o.panel},D));if(a){var x=m("div",{class:o.detachedSearchButtonIcon,children:[at({environment:i})]}),N=m("div",{class:o.detachedSearchButtonPlaceholder,textContent:l}),q=m("button",{type:"button",class:o.detachedSearchButton,onClick:function(){p(!0)},children:[x,N]}),R=m("button",{type:"button",class:o.detachedCancelButton,textContent:d.detachedCancelButtonText,onTouchStart:function(e){e.stopPropagation()},onClick:function(){t.setIsOpen(!1),p(!1)}}),T=m("div",{class:o.detachedFormContainer,children:[C,R]});g.appendChild(T),h.appendChild(q)}else h.appendChild(C);return{detachedContainer:g,detachedOverlay:y,inputWrapper:E,input:w,root:h,form:C,label:_,submitButton:O,clearButton:P,loadingIndicator:j,panel:k}}var lt,st,pt,ft,dt,mt,vt={},ht=[],gt=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord|itera/i;function yt(e,t){for(var n in t)e[n]=t[n];return e}function bt(e){var t=e.parentNode;t&&t.removeChild(e)}function Ot(e,t,n){var r,o,i,u={};for(i in t)"key"==i?r=t[i]:"ref"==i?o=t[i]:u[i]=t[i];if(arguments.length>2&&(u.children=arguments.length>3?lt.call(arguments,2):n),"function"==typeof e&&null!=e.defaultProps)for(i in e.defaultProps)void 0===u[i]&&(u[i]=e.defaultProps[i]);return _t(e,u,r,o,null)}function _t(e,t,n,r,o){var i={type:e,props:t,key:n,ref:r,__k:null,__:null,__b:0,__e:null,__d:void 0,__c:null,__h:null,constructor:void 0,__v:null==o?++pt:o};return null==o&&null!=st.vnode&&st.vnode(i),i}function Pt(e){return e.children}function jt(e,t){this.props=e,this.context=t}function wt(e,t){if(null==t)return e.__?wt(e.__,e.__.__k.indexOf(e)+1):null;for(var n;t<e.__k.length;t++)if(null!=(n=e.__k[t])&&null!=n.__e)return n.__e;return"function"==typeof e.type?wt(e):null}function St(e){var t,n;if(null!=(e=e.__)&&null!=e.__c){for(e.__e=e.__c.base=null,t=0;t<e.__k.length;t++)if(null!=(n=e.__k[t])&&null!=n.__e){e.__e=e.__c.base=n.__e;break}return St(e)}}function It(e){(!e.__d&&(e.__d=!0)&&ft.push(e)&&!Et.__r++||mt!==st.debounceRendering)&&((mt=st.debounceRendering)||dt)(Et)}function Et(){for(var e;Et.__r=ft.length;)e=ft.sort((function(e,t){return e.__v.__b-t.__v.__b})),ft=[],e.some((function(e){var t,n,r,o,i,u;e.__d&&(i=(o=(t=e).__v).__e,(u=t.__P)&&(n=[],(r=yt({},o)).__v=o.__v+1,Rt(u,o,r,t.__n,void 0!==u.ownerSVGElement,null!=o.__h?[i]:null,n,null==i?wt(o):i,o.__h),Tt(n,o),o.__e!=i&&St(o)))}))}function At(e,t,n,r,o,i,u,a,c,l){var s,p,f,d,m,v,h,g=r&&r.__k||ht,y=g.length;for(n.__k=[],s=0;s<t.length;s++)if(null!=(d=n.__k[s]=null==(d=t[s])||"boolean"==typeof d?null:"string"==typeof d||"number"==typeof d||"bigint"==typeof d?_t(null,d,null,null,d):Array.isArray(d)?_t(Pt,{children:d},null,null,null):d.__b>0?_t(d.type,d.props,d.key,null,d.__v):d)){if(d.__=n,d.__b=n.__b+1,null===(f=g[s])||f&&d.key==f.key&&d.type===f.type)g[s]=void 0;else for(p=0;p<y;p++){if((f=g[p])&&d.key==f.key&&d.type===f.type){g[p]=void 0;break}f=null}Rt(e,d,f=f||vt,o,i,u,a,c,l),m=d.__e,(p=d.ref)&&f.ref!=p&&(h||(h=[]),f.ref&&h.push(f.ref,null,d),h.push(p,d.__c||m,d)),null!=m?(null==v&&(v=m),"function"==typeof d.type&&d.__k===f.__k?d.__d=c=Ct(d,c,e):c=Dt(e,d,f,g,m,c),"function"==typeof n.type&&(n.__d=c)):c&&f.__e==c&&c.parentNode!=e&&(c=wt(f))}for(n.__e=v,s=y;s--;)null!=g[s]&&("function"==typeof n.type&&null!=g[s].__e&&g[s].__e==n.__d&&(n.__d=wt(r,s+1)),Ft(g[s],g[s]));if(h)for(s=0;s<h.length;s++)Bt(h[s],h[++s],h[++s])}function Ct(e,t,n){for(var r,o=e.__k,i=0;o&&i<o.length;i++)(r=o[i])&&(r.__=e,t="function"==typeof r.type?Ct(r,t,n):Dt(n,r,r,o,r.__e,t));return t}function Dt(e,t,n,r,o,i){var u,a,c;if(void 0!==t.__d)u=t.__d,t.__d=void 0;else if(null==n||o!=i||null==o.parentNode)e:if(null==i||i.parentNode!==e)e.appendChild(o),u=null;else{for(a=i,c=0;(a=a.nextSibling)&&c<r.length;c+=2)if(a==o)break e;e.insertBefore(o,i),u=i}return void 0!==u?u:o.nextSibling}function kt(e,t,n){"-"===t[0]?e.setProperty(t,n):e[t]=null==n?"":"number"!=typeof n||gt.test(t)?n:n+"px"}function xt(e,t,n,r,o){var i;e:if("style"===t)if("string"==typeof n)e.style.cssText=n;else{if("string"==typeof r&&(e.style.cssText=r=""),r)for(t in r)n&&t in n||kt(e.style,t,"");if(n)for(t in n)r&&n[t]===r[t]||kt(e.style,t,n[t])}else if("o"===t[0]&&"n"===t[1])i=t!==(t=t.replace(/Capture$/,"")),t=t.toLowerCase()in e?t.toLowerCase().slice(2):t.slice(2),e.l||(e.l={}),e.l[t+i]=n,n?r||e.addEventListener(t,i?qt:Nt,i):e.removeEventListener(t,i?qt:Nt,i);else if("dangerouslySetInnerHTML"!==t){if(o)t=t.replace(/xlink[H:h]/,"h").replace(/sName$/,"s");else if("href"!==t&&"list"!==t&&"form"!==t&&"tabIndex"!==t&&"download"!==t&&t in e)try{e[t]=null==n?"":n;break e}catch(e){}"function"==typeof n||(null!=n&&(!1!==n||"a"===t[0]&&"r"===t[1])?e.setAttribute(t,n):e.removeAttribute(t))}}function Nt(e){this.l[e.type+!1](st.event?st.event(e):e)}function qt(e){this.l[e.type+!0](st.event?st.event(e):e)}function Rt(e,t,n,r,o,i,u,a,c){var l,s,p,f,d,m,v,h,g,y,b,O=t.type;if(void 0!==t.constructor)return null;null!=n.__h&&(c=n.__h,a=t.__e=n.__e,t.__h=null,i=[a]),(l=st.__b)&&l(t);try{e:if("function"==typeof O){if(h=t.props,g=(l=O.contextType)&&r[l.__c],y=l?g?g.props.value:l.__:r,n.__c?v=(s=t.__c=n.__c).__=s.__E:("prototype"in O&&O.prototype.render?t.__c=s=new O(h,y):(t.__c=s=new jt(h,y),s.constructor=O,s.render=Mt),g&&g.sub(s),s.props=h,s.state||(s.state={}),s.context=y,s.__n=r,p=s.__d=!0,s.__h=[]),null==s.__s&&(s.__s=s.state),null!=O.getDerivedStateFromProps&&(s.__s==s.state&&(s.__s=yt({},s.__s)),yt(s.__s,O.getDerivedStateFromProps(h,s.__s))),f=s.props,d=s.state,p)null==O.getDerivedStateFromProps&&null!=s.componentWillMount&&s.componentWillMount(),null!=s.componentDidMount&&s.__h.push(s.componentDidMount);else{if(null==O.getDerivedStateFromProps&&h!==f&&null!=s.componentWillReceiveProps&&s.componentWillReceiveProps(h,y),!s.__e&&null!=s.shouldComponentUpdate&&!1===s.shouldComponentUpdate(h,s.__s,y)||t.__v===n.__v){s.props=h,s.state=s.__s,t.__v!==n.__v&&(s.__d=!1),s.__v=t,t.__e=n.__e,t.__k=n.__k,t.__k.forEach((function(e){e&&(e.__=t)})),s.__h.length&&u.push(s);break e}null!=s.componentWillUpdate&&s.componentWillUpdate(h,s.__s,y),null!=s.componentDidUpdate&&s.__h.push((function(){s.componentDidUpdate(f,d,m)}))}s.context=y,s.props=h,s.state=s.__s,(l=st.__r)&&l(t),s.__d=!1,s.__v=t,s.__P=e,l=s.render(s.props,s.state,s.context),s.state=s.__s,null!=s.getChildContext&&(r=yt(yt({},r),s.getChildContext())),p||null==s.getSnapshotBeforeUpdate||(m=s.getSnapshotBeforeUpdate(f,d)),b=null!=l&&l.type===Pt&&null==l.key?l.props.children:l,At(e,Array.isArray(b)?b:[b],t,n,r,o,i,u,a,c),s.base=t.__e,t.__h=null,s.__h.length&&u.push(s),v&&(s.__E=s.__=null),s.__e=!1}else null==i&&t.__v===n.__v?(t.__k=n.__k,t.__e=n.__e):t.__e=Lt(n.__e,t,n,r,o,i,u,c);(l=st.diffed)&&l(t)}catch(e){t.__v=null,(c||null!=i)&&(t.__e=a,t.__h=!!c,i[i.indexOf(a)]=null),st.__e(e,t,n)}}function Tt(e,t){st.__c&&st.__c(t,e),e.some((function(t){try{e=t.__h,t.__h=[],e.some((function(e){e.call(t)}))}catch(e){st.__e(e,t.__v)}}))}function Lt(e,t,n,r,o,i,u,a){var c,l,s,p=n.props,f=t.props,d=t.type,m=0;if("svg"===d&&(o=!0),null!=i)for(;m<i.length;m++)if((c=i[m])&&"setAttribute"in c==!!d&&(d?c.localName===d:3===c.nodeType)){e=c,i[m]=null;break}if(null==e){if(null===d)return document.createTextNode(f);e=o?document.createElementNS("http://www.w3.org/2000/svg",d):document.createElement(d,f.is&&f),i=null,a=!1}if(null===d)p===f||a&&e.data===f||(e.data=f);else{if(i=i&<.call(e.childNodes),l=(p=n.props||vt).dangerouslySetInnerHTML,s=f.dangerouslySetInnerHTML,!a){if(null!=i)for(p={},m=0;m<e.attributes.length;m++)p[e.attributes[m].name]=e.attributes[m].value;(s||l)&&(s&&(l&&s.__html==l.__html||s.__html===e.innerHTML)||(e.innerHTML=s&&s.__html||""))}if(function(e,t,n,r,o){var i;for(i in n)"children"===i||"key"===i||i in t||xt(e,i,null,n[i],r);for(i in t)o&&"function"!=typeof t[i]||"children"===i||"key"===i||"value"===i||"checked"===i||n[i]===t[i]||xt(e,i,t[i],n[i],r)}(e,f,p,o,a),s)t.__k=[];else if(m=t.props.children,At(e,Array.isArray(m)?m:[m],t,n,r,o&&"foreignObject"!==d,i,u,i?i[0]:n.__k&&wt(n,0),a),null!=i)for(m=i.length;m--;)null!=i[m]&&bt(i[m]);a||("value"in f&&void 0!==(m=f.value)&&(m!==p.value||m!==e.value||"progress"===d&&!m)&&xt(e,"value",m,p.value,!1),"checked"in f&&void 0!==(m=f.checked)&&m!==e.checked&&xt(e,"checked",m,p.checked,!1))}return e}function Bt(e,t,n){try{"function"==typeof e?e(t):e.current=t}catch(e){st.__e(e,n)}}function Ft(e,t,n){var r,o;if(st.unmount&&st.unmount(e),(r=e.ref)&&(r.current&&r.current!==e.__e||Bt(r,null,t)),null!=(r=e.__c)){if(r.componentWillUnmount)try{r.componentWillUnmount()}catch(e){st.__e(e,t)}r.base=r.__P=null}if(r=e.__k)for(o=0;o<r.length;o++)r[o]&&Ft(r[o],t,"function"!=typeof e.type);n||null==e.__e||bt(e.__e),e.__e=e.__d=void 0}function Mt(e,t,n){return this.constructor(e,n)}lt=ht.slice,st={__e:function(e,t){for(var n,r,o;t=t.__;)if((n=t.__c)&&!n.__)try{if((r=n.constructor)&&null!=r.getDerivedStateFromError&&(n.setState(r.getDerivedStateFromError(e)),o=n.__d),null!=n.componentDidCatch&&(n.componentDidCatch(e),o=n.__d),o)return n.__E=n}catch(t){e=t}throw e}},pt=0,jt.prototype.setState=function(e,t){var n;n=null!=this.__s&&this.__s!==this.state?this.__s:this.__s=yt({},this.state),"function"==typeof e&&(e=e(yt({},n),this.props)),e&&yt(n,e),null!=e&&this.__v&&(t&&this.__h.push(t),It(this))},jt.prototype.forceUpdate=function(e){this.__v&&(this.__e=!0,e&&this.__h.push(e),It(this))},jt.prototype.render=Pt,ft=[],dt="function"==typeof Promise?Promise.prototype.then.bind(Promise.resolve()):setTimeout,Et.__r=0;var Ut="__aa-highlight__",Ht="__/aa-highlight__";function Vt(e){var t=e.highlightedValue.split(Ut),n=t.shift(),r=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];return{get:function(){return e},add:function(t){var n=e[e.length-1];(null==n?void 0:n.isHighlighted)===t.isHighlighted?e[e.length-1]={value:n.value+t.value,isHighlighted:n.isHighlighted}:e.push(t)}}}(n?[{value:n,isHighlighted:!1}]:[]);return t.forEach((function(e){var t=e.split(Ht);r.add({value:t[0],isHighlighted:!0}),""!==t[1]&&r.add({value:t[1],isHighlighted:!1})})),r.get()}function Wt(e){return function(e){if(Array.isArray(e))return Qt(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,t){if(!e)return;if("string"==typeof e)return Qt(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return Qt(e,t)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function Qt(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n<t;n++)r[n]=e[n];return r}function $t(e){var t=e.hit,n=e.attribute,r=Array.isArray(n)?n:[n],o=h(t,["_highlightResult"].concat(Wt(r),["value"]));return"string"!=typeof o&&(o=h(t,r)||""),Vt({highlightedValue:o})}var zt={"&":"&","<":"<",">":">",""":'"',"'":"'"},Gt=new RegExp(/\w/i),Kt=/&(amp|quot|lt|gt|#39);/g,Jt=RegExp(Kt.source);function Yt(e,t){var n,r,o,i=e[t],u=(null===(n=e[t+1])||void 0===n?void 0:n.isHighlighted)||!0,a=(null===(r=e[t-1])||void 0===r?void 0:r.isHighlighted)||!0;return Gt.test((o=i.value)&&Jt.test(o)?o.replace(Kt,(function(e){return zt[e]})):o)||a!==u?i.isHighlighted:a}function Xt(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function Zt(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?Xt(Object(n),!0).forEach((function(t){en(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):Xt(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function en(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function tn(e){return e.some((function(e){return e.isHighlighted}))?e.map((function(t,n){return Zt(Zt({},t),{},{isHighlighted:!Yt(e,n)})})):e.map((function(e){return Zt(Zt({},e),{},{isHighlighted:!1})}))}function nn(e){return function(e){if(Array.isArray(e))return rn(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,t){if(!e)return;if("string"==typeof e)return rn(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return rn(e,t)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function rn(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n<t;n++)r[n]=e[n];return r}function on(e){var t=e.hit,n=e.attribute,r=Array.isArray(n)?n:[n],o=h(t,["_snippetResult"].concat(nn(r),["value"]));return"string"!=typeof o&&(o=h(t,r)||""),Vt({highlightedValue:o})}function un(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function an(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?un(Object(n),!0).forEach((function(t){cn(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):un(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function cn(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}var ln=["params"];function sn(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function pn(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{};t%2?sn(Object(n),!0).forEach((function(t){fn(e,t,n[t])})):Object.getOwnPropertyDescriptors?Object.defineProperties(e,Object.getOwnPropertyDescriptors(n)):sn(Object(n)).forEach((function(t){Object.defineProperty(e,t,Object.getOwnPropertyDescriptor(n,t))}))}return e}function fn(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function dn(e,t){if(null==e)return{};var n,r,o=function(e,t){if(null==e)return{};var n,r,o={},i=Object.keys(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||(o[n]=e[n]);return o}(e,t);if(Object.getOwnPropertySymbols){var i=Object.getOwnPropertySymbols(e);for(r=0;r<i.length;r++)n=i[r],t.indexOf(n)>=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(o[n]=e[n])}return o}function mn(e){return function(e){if(Array.isArray(e))return vn(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,t){if(!e)return;if("string"==typeof e)return vn(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);"Object"===n&&e.constructor&&(n=e.constructor.name);if("Map"===n||"Set"===n)return Array.from(e);if("Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n))return vn(e,t)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function vn(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n<t;n++)r[n]=e[n];return r}function hn(e){var t=e.createElement,n=e.Fragment;function r(e){var r=e.hit,o=e.attribute,i=e.tagName,u=void 0===i?"mark":i;return t(n,{},$t({hit:r,attribute:o}).map((function(e,n){return e.isHighlighted?t(u,{key:n},e.value):e.value})))}return r.__autocomplete_componentName="Highlight",r}function gn(e){var t=e.createElement,n=e.Fragment;function r(e){var r,o=e.hit,i=e.attribute,u=e.tagName,a=void 0===u?"mark":u;return t(n,{},(r={hit:o,attribute:i},tn($t(r))).map((function(e,n){return e.isHighlighted?t(a,{key:n},e.value):e.value})))}return r.__autocomplete_componentName="ReverseHighlight",r}function yn(e){var t=e.createElement,n=e.Fragment;function r(e){var r,o=e.hit,i=e.attribute,u=e.tagName,a=void 0===u?"mark":u;return t(n,{},(r={hit:o,attribute:i},tn(on(r))).map((function(e,n){return e.isHighlighted?t(a,{key:n},e.value):e.value})))}return r.__autocomplete_componentName="ReverseSnippet",r}function bn(e){var t=e.createElement,n=e.Fragment;function r(e){var r=e.hit,o=e.attribute,i=e.tagName,u=void 0===i?"mark":i;return t(n,{},on({hit:r,attribute:o}).map((function(e,n){return e.isHighlighted?t(u,{key:n},e.value):e.value})))}return r.__autocomplete_componentName="Snippet",r}var On=["classNames","container","getEnvironmentProps","getFormProps","getInputProps","getItemProps","getLabelProps","getListProps","getPanelProps","getRootProps","panelContainer","panelPlacement","render","renderNoResults","renderer","detachedMediaQuery","components","translations"],_n={clearButton:"aa-ClearButton",detachedCancelButton:"aa-DetachedCancelButton",detachedContainer:"aa-DetachedContainer",detachedFormContainer:"aa-DetachedFormContainer",detachedOverlay:"aa-DetachedOverlay",detachedSearchButton:"aa-DetachedSearchButton",detachedSearchButtonIcon:"aa-DetachedSearchButtonIcon",detachedSearchButtonPlaceholder:"aa-DetachedSearchButtonPlaceholder",form:"aa-Form",input:"aa-Input",inputWrapper:"aa-InputWrapper",inputWrapperPrefix:"aa-InputWrapperPrefix",inputWrapperSuffix:"aa-InputWrapperSuffix",item:"aa-Item",label:"aa-Label",list:"aa-List",loadingIndicator:"aa-LoadingIndicator",panel:"aa-Panel",panelLayout:"aa-PanelLayout aa-Panel--scrollable",root:"aa-Autocomplete",source:"aa-Source",sourceFooter:"aa-SourceFooter",sourceHeader:"aa-SourceHeader",sourceNoResults:"aa-SourceNoResults",submitButton:"aa-SubmitButton"},Pn=function(e,t){var n=e.children;(0,e.render)(n,t)},jn={createElement:Ot,Fragment:Pt,render:function(e,t,n){var r,o,i;st.__&&st.__(e,t),o=(r="function"==typeof n)?null:n&&n.__k||t.__k,i=[],Rt(t,e=(!r&&n||t).__k=Ot(Pt,null,[e]),o||vt,vt,void 0!==t.ownerSVGElement,!r&&n?[n]:o?null:t.firstChild?lt.call(t.childNodes):null,i,!r&&n?n:o?o.__e:t.firstChild,r),Tt(i,e)}};function wn(e){var t=e.panelPlacement,n=e.container,r=e.form,o=e.environment,i=n.getBoundingClientRect(),u=(o.pageYOffset||o.document.documentElement.scrollTop||o.document.body.scrollTop||0)+i.top+i.height;switch(t){case"start":return{top:u,left:i.left};case"end":return{top:u,right:o.document.documentElement.clientWidth-(i.left+i.width)};case"full-width":return{top:u,left:0,right:0,width:"unset",maxWidth:"unset"};case"input-wrapper-width":var a=r.getBoundingClientRect();return{top:u,left:a.left,right:o.document.documentElement.clientWidth-(a.left+a.width),width:"unset",maxWidth:"unset"};default:throw new Error("[Autocomplete] The `panelPlacement` value ".concat(JSON.stringify(t)," is not valid."))}}var Sn=[{segment:"autocomplete-js",version:b}],In=["components"];var En=function(e,t){function n(t){return e({searchClient:t.searchClient,queries:t.requests.map((function(e){return e.query}))}).then((function(e){return e.map((function(e,n){var r=t.requests[n];return{items:e,sourceId:r.sourceId,transformResponse:r.transformResponse}}))}))}return function(e){return function(r){return an(an({requesterId:t,execute:n},e),r)}}}((function(e){return function(e){var t=e.searchClient,n=e.queries,r=e.userAgents,o=void 0===r?[]:r;return"function"==typeof t.addAlgoliaAgent&&[].concat(mn(O),mn(o)).forEach((function(e){var n=e.segment,r=e.version;t.addAlgoliaAgent(n,r)})),t.search(n.map((function(e){var t=e.params;return pn(pn({},dn(e,ln)),{},{params:pn({hitsPerPage:5,highlightPreTag:Ut,highlightPostTag:Ht},t)})}))).then((function(e){return e.results}))}(n(n({},e),{},{userAgents:Sn}))}),"algolia");var An=En({transformResponse:function(e){return e.hits}});e.autocomplete=function(e){var t,r=function(){var e=[],t=[];function n(n){e.push(n);var r=n();t.push(r)}return{runEffect:n,cleanupEffects:function(){var e=t;t=[],e.forEach((function(e){e()}))},runEffects:function(){var t=e;e=[],t.forEach((function(e){n(e)}))}}}(),a=r.runEffect,c=r.cleanupEffects,l=r.runEffects,s=(t=[],{reactive:function(e){var n=e(),r={_fn:e,_ref:{current:n},get value(){return this._ref.current},set value(e){this._ref.current=e}};return t.push(r),r},runReactives:function(){t.forEach((function(e){e._ref.current=e._fn()}))}}),d=s.reactive,m=s.runReactives,h=p(!1),y=p(e),b=p(void 0),O=d((function(){return function(e){var t,r=e.classNames,o=e.container,i=e.getEnvironmentProps,a=e.getFormProps,c=e.getInputProps,l=e.getItemProps,s=e.getLabelProps,p=e.getListProps,f=e.getPanelProps,d=e.getRootProps,m=e.panelContainer,h=e.panelPlacement,g=e.render,y=e.renderNoResults,b=e.renderer,O=e.detachedMediaQuery,_=e.components,P=e.translations,j=u(e,On),w="undefined"!=typeof window?window:{},S=Qe(w,o);S.tagName;var I=n(n({},jn),b),E={Highlight:hn(I),ReverseHighlight:gn(I),ReverseSnippet:yn(I),Snippet:bn(I)};return{renderer:{classNames:$e(_n,null!=r?r:{}),container:S,getEnvironmentProps:null!=i?i:function(e){return e.props},getFormProps:null!=a?a:function(e){return e.props},getInputProps:null!=c?c:function(e){return e.props},getItemProps:null!=l?l:function(e){return e.props},getLabelProps:null!=s?s:function(e){return e.props},getListProps:null!=p?p:function(e){return e.props},getPanelProps:null!=f?f:function(e){return e.props},getRootProps:null!=d?d:function(e){return e.props},panelContainer:m?Qe(w,m):w.document.body,panelPlacement:null!=h?h:"input-wrapper-width",render:null!=g?g:Pn,renderNoResults:y,renderer:I,detachedMediaQuery:null!=O?O:getComputedStyle(w.document.documentElement).getPropertyValue("--aa-detached-media-query"),components:n(n({},E),_),translations:n(n({},{clearButtonTitle:"Clear",detachedCancelButtonText:"Cancel",submitButtonTitle:"Submit"}),P)},core:n(n({},j),{},{id:null!==(t=j.id)&&void 0!==t?t:v(),environment:w})}}(y.current)})),_=d((function(){return O.value.core.environment.matchMedia(O.value.renderer.detachedMediaQuery).matches})),P=d((function(){return Me(n(n({},O.value.core),{},{onStateChange:function(e){var t,n,r;h.current=e.state.collections.some((function(e){return e.source.templates.noResults})),null===(t=b.current)||void 0===t||t.call(b,e),null===(n=(r=O.value.core).onStateChange)||void 0===n||n.call(r,e)},shouldPanelOpen:y.current.shouldPanelOpen||function(e){var t=e.state;if(_.value)return!0;var n=g(t)>0;if(!O.value.core.openOnFocus&&!t.query)return n;var r=Boolean(h.current||O.value.renderer.renderNoResults);return!n&&r||n},__autocomplete_metadata:{userAgents:Sn,options:e}}))})),j=p(n({collections:[],completion:null,context:{},isOpen:!1,query:"",activeItemId:null,status:"idle"},O.value.core.initialState)),w={getEnvironmentProps:O.value.renderer.getEnvironmentProps,getFormProps:O.value.renderer.getFormProps,getInputProps:O.value.renderer.getInputProps,getItemProps:O.value.renderer.getItemProps,getLabelProps:O.value.renderer.getLabelProps,getListProps:O.value.renderer.getListProps,getPanelProps:O.value.renderer.getPanelProps,getRootProps:O.value.renderer.getRootProps},S={setActiveItemId:P.value.setActiveItemId,setQuery:P.value.setQuery,setCollections:P.value.setCollections,setIsOpen:P.value.setIsOpen,setStatus:P.value.setStatus,setContext:P.value.setContext,refresh:P.value.refresh},I=d((function(){return Ve.bind(O.value.renderer.renderer.createElement)})),E=d((function(){return ct({autocomplete:P.value,autocompleteScopeApi:S,classNames:O.value.renderer.classNames,environment:O.value.core.environment,isDetached:_.value,placeholder:O.value.core.placeholder,propGetters:w,setIsModalOpen:k,state:j.current,translations:O.value.renderer.translations})}));function A(){tt(E.value.panel,{style:_.value?{}:wn({panelPlacement:O.value.renderer.panelPlacement,container:E.value.root,form:E.value.form,environment:O.value.core.environment})})}function C(e){j.current=e;var t={autocomplete:P.value,autocompleteScopeApi:S,classNames:O.value.renderer.classNames,components:O.value.renderer.components,container:O.value.renderer.container,html:I.value,dom:E.value,panelContainer:_.value?E.value.detachedContainer:O.value.renderer.panelContainer,propGetters:w,state:j.current,renderer:O.value.renderer.renderer},r=!g(e)&&!h.current&&O.value.renderer.renderNoResults||O.value.renderer.render;!function(e){var t=e.autocomplete,r=e.autocompleteScopeApi,o=e.dom,i=e.propGetters,u=e.state;nt(o.root,i.getRootProps(n({state:u,props:t.getRootProps({})},r))),nt(o.input,i.getInputProps(n({state:u,props:t.getInputProps({inputElement:o.input}),inputElement:o.input},r))),tt(o.label,{hidden:"stalled"===u.status}),tt(o.loadingIndicator,{hidden:"stalled"!==u.status}),tt(o.clearButton,{hidden:!u.query})}(t),function(e,t){var r=t.autocomplete,o=t.autocompleteScopeApi,u=t.classNames,a=t.html,c=t.dom,l=t.panelContainer,s=t.propGetters,p=t.state,f=t.components,d=t.renderer;if(p.isOpen){l.contains(c.panel)||"loading"===p.status||l.appendChild(c.panel),c.panel.classList.toggle("aa-Panel--stalled","stalled"===p.status);var m=p.collections.filter((function(e){var t=e.source,n=e.items;return t.templates.noResults||n.length>0})).map((function(e,t){var c=e.source,l=e.items;return d.createElement("section",{key:t,className:u.source,"data-autocomplete-source-id":c.sourceId},c.templates.header&&d.createElement("div",{className:u.sourceHeader},c.templates.header({components:f,createElement:d.createElement,Fragment:d.Fragment,items:l,source:c,state:p,html:a})),c.templates.noResults&&0===l.length?d.createElement("div",{className:u.sourceNoResults},c.templates.noResults({components:f,createElement:d.createElement,Fragment:d.Fragment,source:c,state:p,html:a})):d.createElement("ul",i({className:u.list},s.getListProps(n({state:p,props:r.getListProps({})},o))),l.map((function(e){var t=r.getItemProps({item:e,source:c});return d.createElement("li",i({key:t.id,className:u.item},s.getItemProps(n({state:p,props:t},o))),c.templates.item({components:f,createElement:d.createElement,Fragment:d.Fragment,item:e,state:p,html:a}))}))),c.templates.footer&&d.createElement("div",{className:u.sourceFooter},c.templates.footer({components:f,createElement:d.createElement,Fragment:d.Fragment,items:l,source:c,state:p,html:a})))})),v=d.createElement(d.Fragment,null,d.createElement("div",{className:u.panelLayout},m),d.createElement("div",{className:"aa-GradientBottom"})),h=m.reduce((function(e,t){return e[t.props["data-autocomplete-source-id"]]=t,e}),{});e(n(n({children:v,state:p,sections:m,elements:h},d),{},{components:f,html:a},o),c.panel)}else l.contains(c.panel)&&l.removeChild(c.panel)}(r,t)}function D(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};c();var t=O.value.renderer,n=t.components,r=u(t,In);y.current=Ge(r,O.value.core,{components:Ke(n,(function(e){return!e.value.hasOwnProperty("__autocomplete_componentName")})),initialState:j.current},e),m(),l(),P.value.refresh().then((function(){C(j.current)}))}function k(e){requestAnimationFrame((function(){var t=O.value.core.environment.document.body.contains(E.value.detachedOverlay);e!==t&&(e?(O.value.core.environment.document.body.appendChild(E.value.detachedOverlay),O.value.core.environment.document.body.classList.add("aa-Detached"),E.value.input.focus()):(O.value.core.environment.document.body.removeChild(E.value.detachedOverlay),O.value.core.environment.document.body.classList.remove("aa-Detached"),P.value.setQuery(""),P.value.refresh()))}))}return a((function(){var e=P.value.getEnvironmentProps({formElement:E.value.form,panelElement:E.value.panel,inputElement:E.value.input});return tt(O.value.core.environment,e),function(){tt(O.value.core.environment,Object.keys(e).reduce((function(e,t){return n(n({},e),{},o({},t,void 0))}),{}))}})),a((function(){var e=_.value?O.value.core.environment.document.body:O.value.renderer.panelContainer,t=_.value?E.value.detachedOverlay:E.value.panel;return _.value&&j.current.isOpen&&k(!0),C(j.current),function(){e.contains(t)&&e.removeChild(t)}})),a((function(){var e=O.value.renderer.container;return e.appendChild(E.value.root),function(){e.removeChild(E.value.root)}})),a((function(){var e=f((function(e){C(e.state)}),0);return b.current=function(t){var n=t.state,r=t.prevState;(_.value&&r.isOpen!==n.isOpen&&k(n.isOpen),_.value||!n.isOpen||r.isOpen||A(),n.query!==r.query)&&O.value.core.environment.document.querySelectorAll(".aa-Panel--scrollable").forEach((function(e){0!==e.scrollTop&&(e.scrollTop=0)}));e({state:n})},function(){b.current=void 0}})),a((function(){var e=f((function(){var e=_.value;_.value=O.value.core.environment.matchMedia(O.value.renderer.detachedMediaQuery).matches,e!==_.value?D({}):requestAnimationFrame(A)}),20);return O.value.core.environment.addEventListener("resize",e),function(){O.value.core.environment.removeEventListener("resize",e)}})),a((function(){if(!_.value)return function(){};function e(e){E.value.detachedContainer.classList.toggle("aa-DetachedContainer--modal",e)}function t(t){e(t.matches)}var n=O.value.core.environment.matchMedia(getComputedStyle(O.value.core.environment.document.documentElement).getPropertyValue("--aa-detached-modal-media-query"));e(n.matches);var r=Boolean(n.addEventListener);return r?n.addEventListener("change",t):n.addListener(t),function(){r?n.removeEventListener("change",t):n.removeListener(t)}})),a((function(){return requestAnimationFrame(A),function(){}})),n(n({},S),{},{update:D,destroy:function(){c()}})},e.getAlgoliaFacets=function(e){var t=En({transformResponse:function(e){return e.facetHits}}),r=e.queries.map((function(e){return n(n({},e),{},{type:"facet"})}));return t(n(n({},e),{},{queries:r}))},e.getAlgoliaResults=An,Object.defineProperty(e,"__esModule",{value:!0})})); + diff --git a/site_libs/quarto-search/fuse.min.js b/site_libs/quarto-search/fuse.min.js new file mode 100644 index 00000000..adc28356 --- /dev/null +++ b/site_libs/quarto-search/fuse.min.js @@ -0,0 +1,9 @@ +/** + * Fuse.js v6.6.2 - Lightweight fuzzy-search (http://fusejs.io) + * + * Copyright (c) 2022 Kiro Risk (http://kiro.me) + * All Rights Reserved. Apache Software License 2.0 + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ +var e,t;e=this,t=function(){"use strict";function e(e,t){var n=Object.keys(e);if(Object.getOwnPropertySymbols){var r=Object.getOwnPropertySymbols(e);t&&(r=r.filter((function(t){return Object.getOwnPropertyDescriptor(e,t).enumerable}))),n.push.apply(n,r)}return n}function t(t){for(var n=1;n<arguments.length;n++){var r=null!=arguments[n]?arguments[n]:{};n%2?e(Object(r),!0).forEach((function(e){c(t,e,r[e])})):Object.getOwnPropertyDescriptors?Object.defineProperties(t,Object.getOwnPropertyDescriptors(r)):e(Object(r)).forEach((function(e){Object.defineProperty(t,e,Object.getOwnPropertyDescriptor(r,e))}))}return t}function n(e){return n="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},n(e)}function r(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}function i(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}function o(e,t,n){return t&&i(e.prototype,t),n&&i(e,n),Object.defineProperty(e,"prototype",{writable:!1}),e}function c(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function a(e,t){if("function"!=typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function");Object.defineProperty(e,"prototype",{value:Object.create(t&&t.prototype,{constructor:{value:e,writable:!0,configurable:!0}}),writable:!1}),t&&u(e,t)}function s(e){return s=Object.setPrototypeOf?Object.getPrototypeOf:function(e){return e.__proto__||Object.getPrototypeOf(e)},s(e)}function u(e,t){return u=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e},u(e,t)}function h(e,t){if(t&&("object"==typeof t||"function"==typeof t))return t;if(void 0!==t)throw new TypeError("Derived constructors may only return object or undefined");return function(e){if(void 0===e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return e}(e)}function l(e){var t=function(){if("undefined"==typeof Reflect||!Reflect.construct)return!1;if(Reflect.construct.sham)return!1;if("function"==typeof Proxy)return!0;try{return Boolean.prototype.valueOf.call(Reflect.construct(Boolean,[],(function(){}))),!0}catch(e){return!1}}();return function(){var n,r=s(e);if(t){var i=s(this).constructor;n=Reflect.construct(r,arguments,i)}else n=r.apply(this,arguments);return h(this,n)}}function f(e){return function(e){if(Array.isArray(e))return d(e)}(e)||function(e){if("undefined"!=typeof Symbol&&null!=e[Symbol.iterator]||null!=e["@@iterator"])return Array.from(e)}(e)||function(e,t){if(e){if("string"==typeof e)return d(e,t);var n=Object.prototype.toString.call(e).slice(8,-1);return"Object"===n&&e.constructor&&(n=e.constructor.name),"Map"===n||"Set"===n?Array.from(e):"Arguments"===n||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)?d(e,t):void 0}}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}()}function d(e,t){(null==t||t>e.length)&&(t=e.length);for(var n=0,r=new Array(t);n<t;n++)r[n]=e[n];return r}function v(e){return Array.isArray?Array.isArray(e):"[object Array]"===b(e)}function g(e){return"string"==typeof e}function y(e){return"number"==typeof e}function p(e){return!0===e||!1===e||function(e){return m(e)&&null!==e}(e)&&"[object Boolean]"==b(e)}function m(e){return"object"===n(e)}function k(e){return null!=e}function M(e){return!e.trim().length}function b(e){return null==e?void 0===e?"[object Undefined]":"[object Null]":Object.prototype.toString.call(e)}var x=function(e){return"Invalid value for key ".concat(e)},w=function(e){return"Pattern length exceeds max of ".concat(e,".")},L=Object.prototype.hasOwnProperty,S=function(){function e(t){var n=this;r(this,e),this._keys=[],this._keyMap={};var i=0;t.forEach((function(e){var t=_(e);i+=t.weight,n._keys.push(t),n._keyMap[t.id]=t,i+=t.weight})),this._keys.forEach((function(e){e.weight/=i}))}return o(e,[{key:"get",value:function(e){return this._keyMap[e]}},{key:"keys",value:function(){return this._keys}},{key:"toJSON",value:function(){return JSON.stringify(this._keys)}}]),e}();function _(e){var t=null,n=null,r=null,i=1,o=null;if(g(e)||v(e))r=e,t=O(e),n=j(e);else{if(!L.call(e,"name"))throw new Error(function(e){return"Missing ".concat(e," property in key")}("name"));var c=e.name;if(r=c,L.call(e,"weight")&&(i=e.weight)<=0)throw new Error(function(e){return"Property 'weight' in key '".concat(e,"' must be a positive integer")}(c));t=O(c),n=j(c),o=e.getFn}return{path:t,id:n,weight:i,src:r,getFn:o}}function O(e){return v(e)?e:e.split(".")}function j(e){return v(e)?e.join("."):e}var A={useExtendedSearch:!1,getFn:function(e,t){var n=[],r=!1;return function e(t,i,o){if(k(t))if(i[o]){var c=t[i[o]];if(!k(c))return;if(o===i.length-1&&(g(c)||y(c)||p(c)))n.push(function(e){return null==e?"":function(e){if("string"==typeof e)return e;var t=e+"";return"0"==t&&1/e==-1/0?"-0":t}(e)}(c));else if(v(c)){r=!0;for(var a=0,s=c.length;a<s;a+=1)e(c[a],i,o+1)}else i.length&&e(c,i,o+1)}else n.push(t)}(e,g(t)?t.split("."):t,0),r?n:n[0]},ignoreLocation:!1,ignoreFieldNorm:!1,fieldNormWeight:1},I=t(t(t(t({},{isCaseSensitive:!1,includeScore:!1,keys:[],shouldSort:!0,sortFn:function(e,t){return e.score===t.score?e.idx<t.idx?-1:1:e.score<t.score?-1:1}}),{includeMatches:!1,findAllMatches:!1,minMatchCharLength:1}),{location:0,threshold:.6,distance:100}),A),C=/[^ ]+/g;function E(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:1,t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:3,n=new Map,r=Math.pow(10,t);return{get:function(t){var i=t.match(C).length;if(n.has(i))return n.get(i);var o=1/Math.pow(i,.5*e),c=parseFloat(Math.round(o*r)/r);return n.set(i,c),c},clear:function(){n.clear()}}}var $=function(){function e(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},n=t.getFn,i=void 0===n?I.getFn:n,o=t.fieldNormWeight,c=void 0===o?I.fieldNormWeight:o;r(this,e),this.norm=E(c,3),this.getFn=i,this.isCreated=!1,this.setIndexRecords()}return o(e,[{key:"setSources",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];this.docs=e}},{key:"setIndexRecords",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];this.records=e}},{key:"setKeys",value:function(){var e=this,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[];this.keys=t,this._keysMap={},t.forEach((function(t,n){e._keysMap[t.id]=n}))}},{key:"create",value:function(){var e=this;!this.isCreated&&this.docs.length&&(this.isCreated=!0,g(this.docs[0])?this.docs.forEach((function(t,n){e._addString(t,n)})):this.docs.forEach((function(t,n){e._addObject(t,n)})),this.norm.clear())}},{key:"add",value:function(e){var t=this.size();g(e)?this._addString(e,t):this._addObject(e,t)}},{key:"removeAt",value:function(e){this.records.splice(e,1);for(var t=e,n=this.size();t<n;t+=1)this.records[t].i-=1}},{key:"getValueForItemAtKeyId",value:function(e,t){return e[this._keysMap[t]]}},{key:"size",value:function(){return this.records.length}},{key:"_addString",value:function(e,t){if(k(e)&&!M(e)){var n={v:e,i:t,n:this.norm.get(e)};this.records.push(n)}}},{key:"_addObject",value:function(e,t){var n=this,r={i:t,$:{}};this.keys.forEach((function(t,i){var o=t.getFn?t.getFn(e):n.getFn(e,t.path);if(k(o))if(v(o))!function(){for(var e=[],t=[{nestedArrIndex:-1,value:o}];t.length;){var c=t.pop(),a=c.nestedArrIndex,s=c.value;if(k(s))if(g(s)&&!M(s)){var u={v:s,i:a,n:n.norm.get(s)};e.push(u)}else v(s)&&s.forEach((function(e,n){t.push({nestedArrIndex:n,value:e})}))}r.$[i]=e}();else if(g(o)&&!M(o)){var c={v:o,n:n.norm.get(o)};r.$[i]=c}})),this.records.push(r)}},{key:"toJSON",value:function(){return{keys:this.keys,records:this.records}}}]),e}();function F(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},r=n.getFn,i=void 0===r?I.getFn:r,o=n.fieldNormWeight,c=void 0===o?I.fieldNormWeight:o,a=new $({getFn:i,fieldNormWeight:c});return a.setKeys(e.map(_)),a.setSources(t),a.create(),a}function R(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=t.errors,r=void 0===n?0:n,i=t.currentLocation,o=void 0===i?0:i,c=t.expectedLocation,a=void 0===c?0:c,s=t.distance,u=void 0===s?I.distance:s,h=t.ignoreLocation,l=void 0===h?I.ignoreLocation:h,f=r/e.length;if(l)return f;var d=Math.abs(a-o);return u?f+d/u:d?1:f}function N(){for(var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:[],t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:I.minMatchCharLength,n=[],r=-1,i=-1,o=0,c=e.length;o<c;o+=1){var a=e[o];a&&-1===r?r=o:a||-1===r||((i=o-1)-r+1>=t&&n.push([r,i]),r=-1)}return e[o-1]&&o-r>=t&&n.push([r,o-1]),n}var P=32;function W(e){for(var t={},n=0,r=e.length;n<r;n+=1){var i=e.charAt(n);t[i]=(t[i]||0)|1<<r-n-1}return t}var T=function(){function e(t){var n=this,i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},o=i.location,c=void 0===o?I.location:o,a=i.threshold,s=void 0===a?I.threshold:a,u=i.distance,h=void 0===u?I.distance:u,l=i.includeMatches,f=void 0===l?I.includeMatches:l,d=i.findAllMatches,v=void 0===d?I.findAllMatches:d,g=i.minMatchCharLength,y=void 0===g?I.minMatchCharLength:g,p=i.isCaseSensitive,m=void 0===p?I.isCaseSensitive:p,k=i.ignoreLocation,M=void 0===k?I.ignoreLocation:k;if(r(this,e),this.options={location:c,threshold:s,distance:h,includeMatches:f,findAllMatches:v,minMatchCharLength:y,isCaseSensitive:m,ignoreLocation:M},this.pattern=m?t:t.toLowerCase(),this.chunks=[],this.pattern.length){var b=function(e,t){n.chunks.push({pattern:e,alphabet:W(e),startIndex:t})},x=this.pattern.length;if(x>P){for(var w=0,L=x%P,S=x-L;w<S;)b(this.pattern.substr(w,P),w),w+=P;if(L){var _=x-P;b(this.pattern.substr(_),_)}}else b(this.pattern,0)}}return o(e,[{key:"searchIn",value:function(e){var t=this.options,n=t.isCaseSensitive,r=t.includeMatches;if(n||(e=e.toLowerCase()),this.pattern===e){var i={isMatch:!0,score:0};return r&&(i.indices=[[0,e.length-1]]),i}var o=this.options,c=o.location,a=o.distance,s=o.threshold,u=o.findAllMatches,h=o.minMatchCharLength,l=o.ignoreLocation,d=[],v=0,g=!1;this.chunks.forEach((function(t){var n=t.pattern,i=t.alphabet,o=t.startIndex,y=function(e,t,n){var r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:{},i=r.location,o=void 0===i?I.location:i,c=r.distance,a=void 0===c?I.distance:c,s=r.threshold,u=void 0===s?I.threshold:s,h=r.findAllMatches,l=void 0===h?I.findAllMatches:h,f=r.minMatchCharLength,d=void 0===f?I.minMatchCharLength:f,v=r.includeMatches,g=void 0===v?I.includeMatches:v,y=r.ignoreLocation,p=void 0===y?I.ignoreLocation:y;if(t.length>P)throw new Error(w(P));for(var m,k=t.length,M=e.length,b=Math.max(0,Math.min(o,M)),x=u,L=b,S=d>1||g,_=S?Array(M):[];(m=e.indexOf(t,L))>-1;){var O=R(t,{currentLocation:m,expectedLocation:b,distance:a,ignoreLocation:p});if(x=Math.min(O,x),L=m+k,S)for(var j=0;j<k;)_[m+j]=1,j+=1}L=-1;for(var A=[],C=1,E=k+M,$=1<<k-1,F=0;F<k;F+=1){for(var W=0,T=E;W<T;)R(t,{errors:F,currentLocation:b+T,expectedLocation:b,distance:a,ignoreLocation:p})<=x?W=T:E=T,T=Math.floor((E-W)/2+W);E=T;var z=Math.max(1,b-T+1),D=l?M:Math.min(b+T,M)+k,K=Array(D+2);K[D+1]=(1<<F)-1;for(var q=D;q>=z;q-=1){var B=q-1,J=n[e.charAt(B)];if(S&&(_[B]=+!!J),K[q]=(K[q+1]<<1|1)&J,F&&(K[q]|=(A[q+1]|A[q])<<1|1|A[q+1]),K[q]&$&&(C=R(t,{errors:F,currentLocation:B,expectedLocation:b,distance:a,ignoreLocation:p}))<=x){if(x=C,(L=B)<=b)break;z=Math.max(1,2*b-L)}}if(R(t,{errors:F+1,currentLocation:b,expectedLocation:b,distance:a,ignoreLocation:p})>x)break;A=K}var U={isMatch:L>=0,score:Math.max(.001,C)};if(S){var V=N(_,d);V.length?g&&(U.indices=V):U.isMatch=!1}return U}(e,n,i,{location:c+o,distance:a,threshold:s,findAllMatches:u,minMatchCharLength:h,includeMatches:r,ignoreLocation:l}),p=y.isMatch,m=y.score,k=y.indices;p&&(g=!0),v+=m,p&&k&&(d=[].concat(f(d),f(k)))}));var y={isMatch:g,score:g?v/this.chunks.length:1};return g&&r&&(y.indices=d),y}}]),e}(),z=function(){function e(t){r(this,e),this.pattern=t}return o(e,[{key:"search",value:function(){}}],[{key:"isMultiMatch",value:function(e){return D(e,this.multiRegex)}},{key:"isSingleMatch",value:function(e){return D(e,this.singleRegex)}}]),e}();function D(e,t){var n=e.match(t);return n?n[1]:null}var K=function(e){a(n,e);var t=l(n);function n(e){return r(this,n),t.call(this,e)}return o(n,[{key:"search",value:function(e){var t=e===this.pattern;return{isMatch:t,score:t?0:1,indices:[0,this.pattern.length-1]}}}],[{key:"type",get:function(){return"exact"}},{key:"multiRegex",get:function(){return/^="(.*)"$/}},{key:"singleRegex",get:function(){return/^=(.*)$/}}]),n}(z),q=function(e){a(n,e);var t=l(n);function n(e){return r(this,n),t.call(this,e)}return o(n,[{key:"search",value:function(e){var t=-1===e.indexOf(this.pattern);return{isMatch:t,score:t?0:1,indices:[0,e.length-1]}}}],[{key:"type",get:function(){return"inverse-exact"}},{key:"multiRegex",get:function(){return/^!"(.*)"$/}},{key:"singleRegex",get:function(){return/^!(.*)$/}}]),n}(z),B=function(e){a(n,e);var t=l(n);function n(e){return r(this,n),t.call(this,e)}return o(n,[{key:"search",value:function(e){var t=e.startsWith(this.pattern);return{isMatch:t,score:t?0:1,indices:[0,this.pattern.length-1]}}}],[{key:"type",get:function(){return"prefix-exact"}},{key:"multiRegex",get:function(){return/^\^"(.*)"$/}},{key:"singleRegex",get:function(){return/^\^(.*)$/}}]),n}(z),J=function(e){a(n,e);var t=l(n);function n(e){return r(this,n),t.call(this,e)}return o(n,[{key:"search",value:function(e){var t=!e.startsWith(this.pattern);return{isMatch:t,score:t?0:1,indices:[0,e.length-1]}}}],[{key:"type",get:function(){return"inverse-prefix-exact"}},{key:"multiRegex",get:function(){return/^!\^"(.*)"$/}},{key:"singleRegex",get:function(){return/^!\^(.*)$/}}]),n}(z),U=function(e){a(n,e);var t=l(n);function n(e){return r(this,n),t.call(this,e)}return o(n,[{key:"search",value:function(e){var t=e.endsWith(this.pattern);return{isMatch:t,score:t?0:1,indices:[e.length-this.pattern.length,e.length-1]}}}],[{key:"type",get:function(){return"suffix-exact"}},{key:"multiRegex",get:function(){return/^"(.*)"\$$/}},{key:"singleRegex",get:function(){return/^(.*)\$$/}}]),n}(z),V=function(e){a(n,e);var t=l(n);function n(e){return r(this,n),t.call(this,e)}return o(n,[{key:"search",value:function(e){var t=!e.endsWith(this.pattern);return{isMatch:t,score:t?0:1,indices:[0,e.length-1]}}}],[{key:"type",get:function(){return"inverse-suffix-exact"}},{key:"multiRegex",get:function(){return/^!"(.*)"\$$/}},{key:"singleRegex",get:function(){return/^!(.*)\$$/}}]),n}(z),G=function(e){a(n,e);var t=l(n);function n(e){var i,o=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},c=o.location,a=void 0===c?I.location:c,s=o.threshold,u=void 0===s?I.threshold:s,h=o.distance,l=void 0===h?I.distance:h,f=o.includeMatches,d=void 0===f?I.includeMatches:f,v=o.findAllMatches,g=void 0===v?I.findAllMatches:v,y=o.minMatchCharLength,p=void 0===y?I.minMatchCharLength:y,m=o.isCaseSensitive,k=void 0===m?I.isCaseSensitive:m,M=o.ignoreLocation,b=void 0===M?I.ignoreLocation:M;return r(this,n),(i=t.call(this,e))._bitapSearch=new T(e,{location:a,threshold:u,distance:l,includeMatches:d,findAllMatches:g,minMatchCharLength:p,isCaseSensitive:k,ignoreLocation:b}),i}return o(n,[{key:"search",value:function(e){return this._bitapSearch.searchIn(e)}}],[{key:"type",get:function(){return"fuzzy"}},{key:"multiRegex",get:function(){return/^"(.*)"$/}},{key:"singleRegex",get:function(){return/^(.*)$/}}]),n}(z),H=function(e){a(n,e);var t=l(n);function n(e){return r(this,n),t.call(this,e)}return o(n,[{key:"search",value:function(e){for(var t,n=0,r=[],i=this.pattern.length;(t=e.indexOf(this.pattern,n))>-1;)n=t+i,r.push([t,n-1]);var o=!!r.length;return{isMatch:o,score:o?0:1,indices:r}}}],[{key:"type",get:function(){return"include"}},{key:"multiRegex",get:function(){return/^'"(.*)"$/}},{key:"singleRegex",get:function(){return/^'(.*)$/}}]),n}(z),Q=[K,H,B,J,V,U,q,G],X=Q.length,Y=/ +(?=(?:[^\"]*\"[^\"]*\")*[^\"]*$)/;function Z(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{};return e.split("|").map((function(e){for(var n=e.trim().split(Y).filter((function(e){return e&&!!e.trim()})),r=[],i=0,o=n.length;i<o;i+=1){for(var c=n[i],a=!1,s=-1;!a&&++s<X;){var u=Q[s],h=u.isMultiMatch(c);h&&(r.push(new u(h,t)),a=!0)}if(!a)for(s=-1;++s<X;){var l=Q[s],f=l.isSingleMatch(c);if(f){r.push(new l(f,t));break}}}return r}))}var ee=new Set([G.type,H.type]),te=function(){function e(t){var n=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},i=n.isCaseSensitive,o=void 0===i?I.isCaseSensitive:i,c=n.includeMatches,a=void 0===c?I.includeMatches:c,s=n.minMatchCharLength,u=void 0===s?I.minMatchCharLength:s,h=n.ignoreLocation,l=void 0===h?I.ignoreLocation:h,f=n.findAllMatches,d=void 0===f?I.findAllMatches:f,v=n.location,g=void 0===v?I.location:v,y=n.threshold,p=void 0===y?I.threshold:y,m=n.distance,k=void 0===m?I.distance:m;r(this,e),this.query=null,this.options={isCaseSensitive:o,includeMatches:a,minMatchCharLength:u,findAllMatches:d,ignoreLocation:l,location:g,threshold:p,distance:k},this.pattern=o?t:t.toLowerCase(),this.query=Z(this.pattern,this.options)}return o(e,[{key:"searchIn",value:function(e){var t=this.query;if(!t)return{isMatch:!1,score:1};var n=this.options,r=n.includeMatches;e=n.isCaseSensitive?e:e.toLowerCase();for(var i=0,o=[],c=0,a=0,s=t.length;a<s;a+=1){var u=t[a];o.length=0,i=0;for(var h=0,l=u.length;h<l;h+=1){var d=u[h],v=d.search(e),g=v.isMatch,y=v.indices,p=v.score;if(!g){c=0,i=0,o.length=0;break}if(i+=1,c+=p,r){var m=d.constructor.type;ee.has(m)?o=[].concat(f(o),f(y)):o.push(y)}}if(i){var k={isMatch:!0,score:c/i};return r&&(k.indices=o),k}}return{isMatch:!1,score:1}}}],[{key:"condition",value:function(e,t){return t.useExtendedSearch}}]),e}(),ne=[];function re(e,t){for(var n=0,r=ne.length;n<r;n+=1){var i=ne[n];if(i.condition(e,t))return new i(e,t)}return new T(e,t)}var ie="$and",oe="$or",ce="$path",ae="$val",se=function(e){return!(!e[ie]&&!e[oe])},ue=function(e){return!!e[ce]},he=function(e){return!v(e)&&m(e)&&!se(e)},le=function(e){return c({},ie,Object.keys(e).map((function(t){return c({},t,e[t])})))};function fe(e,t){var n=t.ignoreFieldNorm,r=void 0===n?I.ignoreFieldNorm:n;e.forEach((function(e){var t=1;e.matches.forEach((function(e){var n=e.key,i=e.norm,o=e.score,c=n?n.weight:null;t*=Math.pow(0===o&&c?Number.EPSILON:o,(c||1)*(r?1:i))})),e.score=t}))}function de(e,t){var n=e.matches;t.matches=[],k(n)&&n.forEach((function(e){if(k(e.indices)&&e.indices.length){var n={indices:e.indices,value:e.value};e.key&&(n.key=e.key.src),e.idx>-1&&(n.refIndex=e.idx),t.matches.push(n)}}))}function ve(e,t){t.score=e.score}function ge(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:{},r=n.includeMatches,i=void 0===r?I.includeMatches:r,o=n.includeScore,c=void 0===o?I.includeScore:o,a=[];return i&&a.push(de),c&&a.push(ve),e.map((function(e){var n=e.idx,r={item:t[n],refIndex:n};return a.length&&a.forEach((function(t){t(e,r)})),r}))}var ye=function(){function e(n){var i=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},o=arguments.length>2?arguments[2]:void 0;r(this,e),this.options=t(t({},I),i),this.options.useExtendedSearch,this._keyStore=new S(this.options.keys),this.setCollection(n,o)}return o(e,[{key:"setCollection",value:function(e,t){if(this._docs=e,t&&!(t instanceof $))throw new Error("Incorrect 'index' type");this._myIndex=t||F(this.options.keys,this._docs,{getFn:this.options.getFn,fieldNormWeight:this.options.fieldNormWeight})}},{key:"add",value:function(e){k(e)&&(this._docs.push(e),this._myIndex.add(e))}},{key:"remove",value:function(){for(var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:function(){return!1},t=[],n=0,r=this._docs.length;n<r;n+=1){var i=this._docs[n];e(i,n)&&(this.removeAt(n),n-=1,r-=1,t.push(i))}return t}},{key:"removeAt",value:function(e){this._docs.splice(e,1),this._myIndex.removeAt(e)}},{key:"getIndex",value:function(){return this._myIndex}},{key:"search",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=t.limit,r=void 0===n?-1:n,i=this.options,o=i.includeMatches,c=i.includeScore,a=i.shouldSort,s=i.sortFn,u=i.ignoreFieldNorm,h=g(e)?g(this._docs[0])?this._searchStringList(e):this._searchObjectList(e):this._searchLogical(e);return fe(h,{ignoreFieldNorm:u}),a&&h.sort(s),y(r)&&r>-1&&(h=h.slice(0,r)),ge(h,this._docs,{includeMatches:o,includeScore:c})}},{key:"_searchStringList",value:function(e){var t=re(e,this.options),n=this._myIndex.records,r=[];return n.forEach((function(e){var n=e.v,i=e.i,o=e.n;if(k(n)){var c=t.searchIn(n),a=c.isMatch,s=c.score,u=c.indices;a&&r.push({item:n,idx:i,matches:[{score:s,value:n,norm:o,indices:u}]})}})),r}},{key:"_searchLogical",value:function(e){var t=this,n=function(e,t){var n=(arguments.length>2&&void 0!==arguments[2]?arguments[2]:{}).auto,r=void 0===n||n,i=function e(n){var i=Object.keys(n),o=ue(n);if(!o&&i.length>1&&!se(n))return e(le(n));if(he(n)){var c=o?n[ce]:i[0],a=o?n[ae]:n[c];if(!g(a))throw new Error(x(c));var s={keyId:j(c),pattern:a};return r&&(s.searcher=re(a,t)),s}var u={children:[],operator:i[0]};return i.forEach((function(t){var r=n[t];v(r)&&r.forEach((function(t){u.children.push(e(t))}))})),u};return se(e)||(e=le(e)),i(e)}(e,this.options),r=function e(n,r,i){if(!n.children){var o=n.keyId,c=n.searcher,a=t._findMatches({key:t._keyStore.get(o),value:t._myIndex.getValueForItemAtKeyId(r,o),searcher:c});return a&&a.length?[{idx:i,item:r,matches:a}]:[]}for(var s=[],u=0,h=n.children.length;u<h;u+=1){var l=e(n.children[u],r,i);if(l.length)s.push.apply(s,f(l));else if(n.operator===ie)return[]}return s},i=this._myIndex.records,o={},c=[];return i.forEach((function(e){var t=e.$,i=e.i;if(k(t)){var a=r(n,t,i);a.length&&(o[i]||(o[i]={idx:i,item:t,matches:[]},c.push(o[i])),a.forEach((function(e){var t,n=e.matches;(t=o[i].matches).push.apply(t,f(n))})))}})),c}},{key:"_searchObjectList",value:function(e){var t=this,n=re(e,this.options),r=this._myIndex,i=r.keys,o=r.records,c=[];return o.forEach((function(e){var r=e.$,o=e.i;if(k(r)){var a=[];i.forEach((function(e,i){a.push.apply(a,f(t._findMatches({key:e,value:r[i],searcher:n})))})),a.length&&c.push({idx:o,item:r,matches:a})}})),c}},{key:"_findMatches",value:function(e){var t=e.key,n=e.value,r=e.searcher;if(!k(n))return[];var i=[];if(v(n))n.forEach((function(e){var n=e.v,o=e.i,c=e.n;if(k(n)){var a=r.searchIn(n),s=a.isMatch,u=a.score,h=a.indices;s&&i.push({score:u,key:t,value:n,idx:o,norm:c,indices:h})}}));else{var o=n.v,c=n.n,a=r.searchIn(o),s=a.isMatch,u=a.score,h=a.indices;s&&i.push({score:u,key:t,value:o,norm:c,indices:h})}return i}}]),e}();return ye.version="6.6.2",ye.createIndex=F,ye.parseIndex=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=t.getFn,r=void 0===n?I.getFn:n,i=t.fieldNormWeight,o=void 0===i?I.fieldNormWeight:i,c=e.keys,a=e.records,s=new $({getFn:r,fieldNormWeight:o});return s.setKeys(c),s.setIndexRecords(a),s},ye.config=I,function(){ne.push.apply(ne,arguments)}(te),ye},"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e="undefined"!=typeof globalThis?globalThis:e||self).Fuse=t(); \ No newline at end of file diff --git a/site_libs/quarto-search/quarto-search.js b/site_libs/quarto-search/quarto-search.js new file mode 100644 index 00000000..f5d852d1 --- /dev/null +++ b/site_libs/quarto-search/quarto-search.js @@ -0,0 +1,1140 @@ +const kQueryArg = "q"; +const kResultsArg = "show-results"; + +// If items don't provide a URL, then both the navigator and the onSelect +// function aren't called (and therefore, the default implementation is used) +// +// We're using this sentinel URL to signal to those handlers that this +// item is a more item (along with the type) and can be handled appropriately +const kItemTypeMoreHref = "0767FDFD-0422-4E5A-BC8A-3BE11E5BBA05"; + +window.document.addEventListener("DOMContentLoaded", function (_event) { + // Ensure that search is available on this page. If it isn't, + // should return early and not do anything + var searchEl = window.document.getElementById("quarto-search"); + if (!searchEl) return; + + const { autocomplete } = window["@algolia/autocomplete-js"]; + + let quartoSearchOptions = {}; + let language = {}; + const searchOptionEl = window.document.getElementById( + "quarto-search-options" + ); + if (searchOptionEl) { + const jsonStr = searchOptionEl.textContent; + quartoSearchOptions = JSON.parse(jsonStr); + language = quartoSearchOptions.language; + } + + // note the search mode + if (quartoSearchOptions.type === "overlay") { + searchEl.classList.add("type-overlay"); + } else { + searchEl.classList.add("type-textbox"); + } + + // Used to determine highlighting behavior for this page + // A `q` query param is expected when the user follows a search + // to this page + const currentUrl = new URL(window.location); + const query = currentUrl.searchParams.get(kQueryArg); + const showSearchResults = currentUrl.searchParams.get(kResultsArg); + const mainEl = window.document.querySelector("main"); + + // highlight matches on the page + if (query !== null && mainEl) { + // perform any highlighting + highlight(escapeRegExp(query), mainEl); + + // fix up the URL to remove the q query param + const replacementUrl = new URL(window.location); + replacementUrl.searchParams.delete(kQueryArg); + window.history.replaceState({}, "", replacementUrl); + } + + // function to clear highlighting on the page when the search query changes + // (e.g. if the user edits the query or clears it) + let highlighting = true; + const resetHighlighting = (searchTerm) => { + if (mainEl && highlighting && query !== null && searchTerm !== query) { + clearHighlight(query, mainEl); + highlighting = false; + } + }; + + // Clear search highlighting when the user scrolls sufficiently + const resetFn = () => { + resetHighlighting(""); + window.removeEventListener("quarto-hrChanged", resetFn); + window.removeEventListener("quarto-sectionChanged", resetFn); + }; + + // Register this event after the initial scrolling and settling of events + // on the page + window.addEventListener("quarto-hrChanged", resetFn); + window.addEventListener("quarto-sectionChanged", resetFn); + + // Responsively switch to overlay mode if the search is present on the navbar + // Note that switching the sidebar to overlay mode requires more coordinate (not just + // the media query since we generate different HTML for sidebar overlays than we do + // for sidebar input UI) + const detachedMediaQuery = + quartoSearchOptions.type === "overlay" ? "all" : "(max-width: 991px)"; + + // If configured, include the analytics client to send insights + const plugins = configurePlugins(quartoSearchOptions); + + let lastState = null; + const { setIsOpen, setQuery, setCollections } = autocomplete({ + container: searchEl, + detachedMediaQuery: detachedMediaQuery, + defaultActiveItemId: 0, + panelContainer: "#quarto-search-results", + panelPlacement: quartoSearchOptions["panel-placement"], + debug: false, + openOnFocus: true, + plugins, + classNames: { + form: "d-flex", + }, + translations: { + clearButtonTitle: language["search-clear-button-title"], + detachedCancelButtonText: language["search-detached-cancel-button-title"], + submitButtonTitle: language["search-submit-button-title"], + }, + initialState: { + query, + }, + getItemUrl({ item }) { + return item.href; + }, + onStateChange({ state }) { + // Perhaps reset highlighting + resetHighlighting(state.query); + + // If the panel just opened, ensure the panel is positioned properly + if (state.isOpen) { + if (lastState && !lastState.isOpen) { + setTimeout(() => { + positionPanel(quartoSearchOptions["panel-placement"]); + }, 150); + } + } + + // Perhaps show the copy link + showCopyLink(state.query, quartoSearchOptions); + + lastState = state; + }, + reshape({ sources, state }) { + return sources.map((source) => { + try { + const items = source.getItems(); + + // Validate the items + validateItems(items); + + // group the items by document + const groupedItems = new Map(); + items.forEach((item) => { + const hrefParts = item.href.split("#"); + const baseHref = hrefParts[0]; + const isDocumentItem = hrefParts.length === 1; + + const items = groupedItems.get(baseHref); + if (!items) { + groupedItems.set(baseHref, [item]); + } else { + // If the href for this item matches the document + // exactly, place this item first as it is the item that represents + // the document itself + if (isDocumentItem) { + items.unshift(item); + } else { + items.push(item); + } + groupedItems.set(baseHref, items); + } + }); + + const reshapedItems = []; + let count = 1; + for (const [_key, value] of groupedItems) { + const firstItem = value[0]; + reshapedItems.push({ + ...firstItem, + type: kItemTypeDoc, + }); + + const collapseMatches = quartoSearchOptions["collapse-after"]; + const collapseCount = + typeof collapseMatches === "number" ? collapseMatches : 1; + + if (value.length > 1) { + const target = `search-more-${count}`; + const isExpanded = + state.context.expanded && + state.context.expanded.includes(target); + + const remainingCount = value.length - collapseCount; + + for (let i = 1; i < value.length; i++) { + if (collapseMatches && i === collapseCount) { + reshapedItems.push({ + target, + title: isExpanded + ? language["search-hide-matches-text"] + : remainingCount === 1 + ? `${remainingCount} ${language["search-more-match-text"]}` + : `${remainingCount} ${language["search-more-matches-text"]}`, + type: kItemTypeMore, + href: kItemTypeMoreHref, + }); + } + + if (isExpanded || !collapseMatches || i < collapseCount) { + reshapedItems.push({ + ...value[i], + type: kItemTypeItem, + target, + }); + } + } + } + count += 1; + } + + return { + ...source, + getItems() { + return reshapedItems; + }, + }; + } catch (error) { + // Some form of error occurred + return { + ...source, + getItems() { + return [ + { + title: error.name || "An Error Occurred While Searching", + text: + error.message || + "An unknown error occurred while attempting to perform the requested search.", + type: kItemTypeError, + }, + ]; + }, + }; + } + }); + }, + navigator: { + navigate({ itemUrl }) { + if (itemUrl !== offsetURL(kItemTypeMoreHref)) { + window.location.assign(itemUrl); + } + }, + navigateNewTab({ itemUrl }) { + if (itemUrl !== offsetURL(kItemTypeMoreHref)) { + const windowReference = window.open(itemUrl, "_blank", "noopener"); + if (windowReference) { + windowReference.focus(); + } + } + }, + navigateNewWindow({ itemUrl }) { + if (itemUrl !== offsetURL(kItemTypeMoreHref)) { + window.open(itemUrl, "_blank", "noopener"); + } + }, + }, + getSources({ state, setContext, setActiveItemId, refresh }) { + return [ + { + sourceId: "documents", + getItemUrl({ item }) { + if (item.href) { + return offsetURL(item.href); + } else { + return undefined; + } + }, + onSelect({ + item, + state, + setContext, + setIsOpen, + setActiveItemId, + refresh, + }) { + if (item.type === kItemTypeMore) { + toggleExpanded(item, state, setContext, setActiveItemId, refresh); + + // Toggle more + setIsOpen(true); + } + }, + getItems({ query }) { + if (query === null || query === "") { + return []; + } + + const limit = quartoSearchOptions.limit; + if (quartoSearchOptions.algolia) { + return algoliaSearch(query, limit, quartoSearchOptions.algolia); + } else { + // Fuse search options + const fuseSearchOptions = { + isCaseSensitive: false, + shouldSort: true, + minMatchCharLength: 2, + limit: limit, + }; + + return readSearchData().then(function (fuse) { + return fuseSearch(query, fuse, fuseSearchOptions); + }); + } + }, + templates: { + noResults({ createElement }) { + const hasQuery = lastState.query; + + return createElement( + "div", + { + class: `quarto-search-no-results${ + hasQuery ? "" : " no-query" + }`, + }, + language["search-no-results-text"] + ); + }, + header({ items, createElement }) { + // count the documents + const count = items.filter((item) => { + return item.type === kItemTypeDoc; + }).length; + + if (count > 0) { + return createElement( + "div", + { class: "search-result-header" }, + `${count} ${language["search-matching-documents-text"]}` + ); + } else { + return createElement( + "div", + { class: "search-result-header-no-results" }, + `` + ); + } + }, + footer({ _items, createElement }) { + if ( + quartoSearchOptions.algolia && + quartoSearchOptions.algolia["show-logo"] + ) { + const libDir = quartoSearchOptions.algolia["libDir"]; + const logo = createElement("img", { + src: offsetURL( + `${libDir}/quarto-search/search-by-algolia.svg` + ), + class: "algolia-search-logo", + }); + return createElement( + "a", + { href: "http://www.algolia.com/" }, + logo + ); + } + }, + + item({ item, createElement }) { + return renderItem( + item, + createElement, + state, + setActiveItemId, + setContext, + refresh + ); + }, + }, + }, + ]; + }, + }); + + window.quartoOpenSearch = () => { + setIsOpen(false); + setIsOpen(true); + focusSearchInput(); + }; + + // Remove the labeleledby attribute since it is pointing + // to a non-existent label + if (quartoSearchOptions.type === "overlay") { + const inputEl = window.document.querySelector( + "#quarto-search .aa-Autocomplete" + ); + if (inputEl) { + inputEl.removeAttribute("aria-labelledby"); + } + } + + // If the main document scrolls dismiss the search results + // (otherwise, since they're floating in the document they can scroll with the document) + window.document.body.onscroll = () => { + setIsOpen(false); + }; + + if (showSearchResults) { + setIsOpen(true); + focusSearchInput(); + } +}); + +function configurePlugins(quartoSearchOptions) { + const autocompletePlugins = []; + const algoliaOptions = quartoSearchOptions.algolia; + if ( + algoliaOptions && + algoliaOptions["analytics-events"] && + algoliaOptions["search-only-api-key"] && + algoliaOptions["application-id"] + ) { + const apiKey = algoliaOptions["search-only-api-key"]; + const appId = algoliaOptions["application-id"]; + + // Aloglia insights may not be loaded because they require cookie consent + // Use deferred loading so events will start being recorded when/if consent + // is granted. + const algoliaInsightsDeferredPlugin = deferredLoadPlugin(() => { + if ( + window.aa && + window["@algolia/autocomplete-plugin-algolia-insights"] + ) { + window.aa("init", { + appId, + apiKey, + useCookie: true, + }); + + const { createAlgoliaInsightsPlugin } = + window["@algolia/autocomplete-plugin-algolia-insights"]; + // Register the insights client + const algoliaInsightsPlugin = createAlgoliaInsightsPlugin({ + insightsClient: window.aa, + onItemsChange({ insights, insightsEvents }) { + const events = insightsEvents.map((event) => { + const maxEvents = event.objectIDs.slice(0, 20); + return { + ...event, + objectIDs: maxEvents, + }; + }); + + insights.viewedObjectIDs(...events); + }, + }); + return algoliaInsightsPlugin; + } + }); + + // Add the plugin + autocompletePlugins.push(algoliaInsightsDeferredPlugin); + return autocompletePlugins; + } +} + +// For plugins that may not load immediately, create a wrapper +// plugin and forward events and plugin data once the plugin +// is initialized. This is useful for cases like cookie consent +// which may prevent the analytics insights event plugin from initializing +// immediately. +function deferredLoadPlugin(createPlugin) { + let plugin = undefined; + let subscribeObj = undefined; + const wrappedPlugin = () => { + if (!plugin && subscribeObj) { + plugin = createPlugin(); + if (plugin && plugin.subscribe) { + plugin.subscribe(subscribeObj); + } + } + return plugin; + }; + + return { + subscribe: (obj) => { + subscribeObj = obj; + }, + onStateChange: (obj) => { + const plugin = wrappedPlugin(); + if (plugin && plugin.onStateChange) { + plugin.onStateChange(obj); + } + }, + onSubmit: (obj) => { + const plugin = wrappedPlugin(); + if (plugin && plugin.onSubmit) { + plugin.onSubmit(obj); + } + }, + onReset: (obj) => { + const plugin = wrappedPlugin(); + if (plugin && plugin.onReset) { + plugin.onReset(obj); + } + }, + getSources: (obj) => { + const plugin = wrappedPlugin(); + if (plugin && plugin.getSources) { + return plugin.getSources(obj); + } else { + return Promise.resolve([]); + } + }, + data: (obj) => { + const plugin = wrappedPlugin(); + if (plugin && plugin.data) { + plugin.data(obj); + } + }, + }; +} + +function validateItems(items) { + // Validate the first item + if (items.length > 0) { + const item = items[0]; + const missingFields = []; + if (item.href == undefined) { + missingFields.push("href"); + } + if (!item.title == undefined) { + missingFields.push("title"); + } + if (!item.text == undefined) { + missingFields.push("text"); + } + + if (missingFields.length === 1) { + throw { + name: `Error: Search index is missing the <code>${missingFields[0]}</code> field.`, + message: `The items being returned for this search do not include all the required fields. Please ensure that your index items include the <code>${missingFields[0]}</code> field or use <code>index-fields</code> in your <code>_quarto.yml</code> file to specify the field names.`, + }; + } else if (missingFields.length > 1) { + const missingFieldList = missingFields + .map((field) => { + return `<code>${field}</code>`; + }) + .join(", "); + + throw { + name: `Error: Search index is missing the following fields: ${missingFieldList}.`, + message: `The items being returned for this search do not include all the required fields. Please ensure that your index items includes the following fields: ${missingFieldList}, or use <code>index-fields</code> in your <code>_quarto.yml</code> file to specify the field names.`, + }; + } + } +} + +let lastQuery = null; +function showCopyLink(query, options) { + const language = options.language; + lastQuery = query; + // Insert share icon + const inputSuffixEl = window.document.body.querySelector( + ".aa-Form .aa-InputWrapperSuffix" + ); + + if (inputSuffixEl) { + let copyButtonEl = window.document.body.querySelector( + ".aa-Form .aa-InputWrapperSuffix .aa-CopyButton" + ); + + if (copyButtonEl === null) { + copyButtonEl = window.document.createElement("button"); + copyButtonEl.setAttribute("class", "aa-CopyButton"); + copyButtonEl.setAttribute("type", "button"); + copyButtonEl.setAttribute("title", language["search-copy-link-title"]); + copyButtonEl.onmousedown = (e) => { + e.preventDefault(); + e.stopPropagation(); + }; + + const linkIcon = "bi-clipboard"; + const checkIcon = "bi-check2"; + + const shareIconEl = window.document.createElement("i"); + shareIconEl.setAttribute("class", `bi ${linkIcon}`); + copyButtonEl.appendChild(shareIconEl); + inputSuffixEl.prepend(copyButtonEl); + + const clipboard = new window.ClipboardJS(".aa-CopyButton", { + text: function (_trigger) { + const copyUrl = new URL(window.location); + copyUrl.searchParams.set(kQueryArg, lastQuery); + copyUrl.searchParams.set(kResultsArg, "1"); + return copyUrl.toString(); + }, + }); + clipboard.on("success", function (e) { + // Focus the input + + // button target + const button = e.trigger; + const icon = button.querySelector("i.bi"); + + // flash "checked" + icon.classList.add(checkIcon); + icon.classList.remove(linkIcon); + setTimeout(function () { + icon.classList.remove(checkIcon); + icon.classList.add(linkIcon); + }, 1000); + }); + } + + // If there is a query, show the link icon + if (copyButtonEl) { + if (lastQuery && options["copy-button"]) { + copyButtonEl.style.display = "flex"; + } else { + copyButtonEl.style.display = "none"; + } + } + } +} + +/* Search Index Handling */ +// create the index +var fuseIndex = undefined; +async function readSearchData() { + // Initialize the search index on demand + if (fuseIndex === undefined) { + // create fuse index + const options = { + keys: [ + { name: "title", weight: 20 }, + { name: "section", weight: 20 }, + { name: "text", weight: 10 }, + ], + ignoreLocation: true, + threshold: 0.1, + }; + const fuse = new window.Fuse([], options); + + // fetch the main search.json + const response = await fetch(offsetURL("search.json")); + if (response.status == 200) { + return response.json().then(function (searchDocs) { + searchDocs.forEach(function (searchDoc) { + fuse.add(searchDoc); + }); + fuseIndex = fuse; + return fuseIndex; + }); + } else { + return Promise.reject( + new Error( + "Unexpected status from search index request: " + response.status + ) + ); + } + } + return fuseIndex; +} + +function inputElement() { + return window.document.body.querySelector(".aa-Form .aa-Input"); +} + +function focusSearchInput() { + setTimeout(() => { + const inputEl = inputElement(); + if (inputEl) { + inputEl.focus(); + } + }, 50); +} + +/* Panels */ +const kItemTypeDoc = "document"; +const kItemTypeMore = "document-more"; +const kItemTypeItem = "document-item"; +const kItemTypeError = "error"; + +function renderItem( + item, + createElement, + state, + setActiveItemId, + setContext, + refresh +) { + switch (item.type) { + case kItemTypeDoc: + return createDocumentCard( + createElement, + "file-richtext", + item.title, + item.section, + item.text, + item.href + ); + case kItemTypeMore: + return createMoreCard( + createElement, + item, + state, + setActiveItemId, + setContext, + refresh + ); + case kItemTypeItem: + return createSectionCard( + createElement, + item.section, + item.text, + item.href + ); + case kItemTypeError: + return createErrorCard(createElement, item.title, item.text); + default: + return undefined; + } +} + +function createDocumentCard(createElement, icon, title, section, text, href) { + const iconEl = createElement("i", { + class: `bi bi-${icon} search-result-icon`, + }); + const titleEl = createElement("p", { class: "search-result-title" }, title); + const titleContainerEl = createElement( + "div", + { class: "search-result-title-container" }, + [iconEl, titleEl] + ); + + const textEls = []; + if (section) { + const sectionEl = createElement( + "p", + { class: "search-result-section" }, + section + ); + textEls.push(sectionEl); + } + const descEl = createElement("p", { + class: "search-result-text", + dangerouslySetInnerHTML: { + __html: text, + }, + }); + textEls.push(descEl); + + const textContainerEl = createElement( + "div", + { class: "search-result-text-container" }, + textEls + ); + + const containerEl = createElement( + "div", + { + class: "search-result-container", + }, + [titleContainerEl, textContainerEl] + ); + + const linkEl = createElement( + "a", + { + href: offsetURL(href), + class: "search-result-link", + }, + containerEl + ); + + const classes = ["search-result-doc", "search-item"]; + if (!section) { + classes.push("document-selectable"); + } + + return createElement( + "div", + { + class: classes.join(" "), + }, + linkEl + ); +} + +function createMoreCard( + createElement, + item, + state, + setActiveItemId, + setContext, + refresh +) { + const moreCardEl = createElement( + "div", + { + class: "search-result-more search-item", + onClick: (e) => { + // Handle expanding the sections by adding the expanded + // section to the list of expanded sections + toggleExpanded(item, state, setContext, setActiveItemId, refresh); + e.stopPropagation(); + }, + }, + item.title + ); + + return moreCardEl; +} + +function toggleExpanded(item, state, setContext, setActiveItemId, refresh) { + const expanded = state.context.expanded || []; + if (expanded.includes(item.target)) { + setContext({ + expanded: expanded.filter((target) => target !== item.target), + }); + } else { + setContext({ expanded: [...expanded, item.target] }); + } + + refresh(); + setActiveItemId(item.__autocomplete_id); +} + +function createSectionCard(createElement, section, text, href) { + const sectionEl = createSection(createElement, section, text, href); + return createElement( + "div", + { + class: "search-result-doc-section search-item", + }, + sectionEl + ); +} + +function createSection(createElement, title, text, href) { + const descEl = createElement("p", { + class: "search-result-text", + dangerouslySetInnerHTML: { + __html: text, + }, + }); + + const titleEl = createElement("p", { class: "search-result-section" }, title); + const linkEl = createElement( + "a", + { + href: offsetURL(href), + class: "search-result-link", + }, + [titleEl, descEl] + ); + return linkEl; +} + +function createErrorCard(createElement, title, text) { + const descEl = createElement("p", { + class: "search-error-text", + dangerouslySetInnerHTML: { + __html: text, + }, + }); + + const titleEl = createElement("p", { + class: "search-error-title", + dangerouslySetInnerHTML: { + __html: `<i class="bi bi-exclamation-circle search-error-icon"></i> ${title}`, + }, + }); + const errorEl = createElement("div", { class: "search-error" }, [ + titleEl, + descEl, + ]); + return errorEl; +} + +function positionPanel(pos) { + const panelEl = window.document.querySelector( + "#quarto-search-results .aa-Panel" + ); + const inputEl = window.document.querySelector( + "#quarto-search .aa-Autocomplete" + ); + + if (panelEl && inputEl) { + panelEl.style.top = `${Math.round(panelEl.offsetTop)}px`; + if (pos === "start") { + panelEl.style.left = `${Math.round(inputEl.left)}px`; + } else { + panelEl.style.right = `${Math.round(inputEl.offsetRight)}px`; + } + } +} + +/* Highlighting */ +// highlighting functions +function highlightMatch(query, text) { + if (text) { + const start = text.toLowerCase().indexOf(query.toLowerCase()); + if (start !== -1) { + const startMark = "<mark class='search-match'>"; + const endMark = "</mark>"; + + const end = start + query.length; + text = + text.slice(0, start) + + startMark + + text.slice(start, end) + + endMark + + text.slice(end); + const startInfo = clipStart(text, start); + const endInfo = clipEnd( + text, + startInfo.position + startMark.length + endMark.length + ); + text = + startInfo.prefix + + text.slice(startInfo.position, endInfo.position) + + endInfo.suffix; + + return text; + } else { + return text; + } + } else { + return text; + } +} + +function clipStart(text, pos) { + const clipStart = pos - 50; + if (clipStart < 0) { + // This will just return the start of the string + return { + position: 0, + prefix: "", + }; + } else { + // We're clipping before the start of the string, walk backwards to the first space. + const spacePos = findSpace(text, pos, -1); + return { + position: spacePos.position, + prefix: "", + }; + } +} + +function clipEnd(text, pos) { + const clipEnd = pos + 200; + if (clipEnd > text.length) { + return { + position: text.length, + suffix: "", + }; + } else { + const spacePos = findSpace(text, clipEnd, 1); + return { + position: spacePos.position, + suffix: spacePos.clipped ? "ā¦" : "", + }; + } +} + +function findSpace(text, start, step) { + let stepPos = start; + while (stepPos > -1 && stepPos < text.length) { + const char = text[stepPos]; + if (char === " " || char === "," || char === ":") { + return { + position: step === 1 ? stepPos : stepPos - step, + clipped: stepPos > 1 && stepPos < text.length, + }; + } + stepPos = stepPos + step; + } + + return { + position: stepPos - step, + clipped: false, + }; +} + +// removes highlighting as implemented by the mark tag +function clearHighlight(searchterm, el) { + const childNodes = el.childNodes; + for (let i = childNodes.length - 1; i >= 0; i--) { + const node = childNodes[i]; + if (node.nodeType === Node.ELEMENT_NODE) { + if ( + node.tagName === "MARK" && + node.innerText.toLowerCase() === searchterm.toLowerCase() + ) { + el.replaceChild(document.createTextNode(node.innerText), node); + } else { + clearHighlight(searchterm, node); + } + } + } +} + +function escapeRegExp(string) { + return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"); // $& means the whole matched string +} + +// highlight matches +function highlight(term, el) { + const termRegex = new RegExp(term, "ig"); + const childNodes = el.childNodes; + + // walk back to front avoid mutating elements in front of us + for (let i = childNodes.length - 1; i >= 0; i--) { + const node = childNodes[i]; + + if (node.nodeType === Node.TEXT_NODE) { + // Search text nodes for text to highlight + const text = node.nodeValue; + + let startIndex = 0; + let matchIndex = text.search(termRegex); + if (matchIndex > -1) { + const markFragment = document.createDocumentFragment(); + while (matchIndex > -1) { + const prefix = text.slice(startIndex, matchIndex); + markFragment.appendChild(document.createTextNode(prefix)); + + const mark = document.createElement("mark"); + mark.appendChild( + document.createTextNode( + text.slice(matchIndex, matchIndex + term.length) + ) + ); + markFragment.appendChild(mark); + + startIndex = matchIndex + term.length; + matchIndex = text.slice(startIndex).search(new RegExp(term, "ig")); + if (matchIndex > -1) { + matchIndex = startIndex + matchIndex; + } + } + if (startIndex < text.length) { + markFragment.appendChild( + document.createTextNode(text.slice(startIndex, text.length)) + ); + } + + el.replaceChild(markFragment, node); + } + } else if (node.nodeType === Node.ELEMENT_NODE) { + // recurse through elements + highlight(term, node); + } + } +} + +/* Link Handling */ +// get the offset from this page for a given site root relative url +function offsetURL(url) { + var offset = getMeta("quarto:offset"); + return offset ? offset + url : url; +} + +// read a meta tag value +function getMeta(metaName) { + var metas = window.document.getElementsByTagName("meta"); + for (let i = 0; i < metas.length; i++) { + if (metas[i].getAttribute("name") === metaName) { + return metas[i].getAttribute("content"); + } + } + return ""; +} + +function algoliaSearch(query, limit, algoliaOptions) { + const { getAlgoliaResults } = window["@algolia/autocomplete-preset-algolia"]; + + const applicationId = algoliaOptions["application-id"]; + const searchOnlyApiKey = algoliaOptions["search-only-api-key"]; + const indexName = algoliaOptions["index-name"]; + const indexFields = algoliaOptions["index-fields"]; + const searchClient = window.algoliasearch(applicationId, searchOnlyApiKey); + const searchParams = algoliaOptions["params"]; + const searchAnalytics = !!algoliaOptions["analytics-events"]; + + return getAlgoliaResults({ + searchClient, + queries: [ + { + indexName: indexName, + query, + params: { + hitsPerPage: limit, + clickAnalytics: searchAnalytics, + ...searchParams, + }, + }, + ], + transformResponse: (response) => { + if (!indexFields) { + return response.hits.map((hit) => { + return hit.map((item) => { + return { + ...item, + text: highlightMatch(query, item.text), + }; + }); + }); + } else { + const remappedHits = response.hits.map((hit) => { + return hit.map((item) => { + const newItem = { ...item }; + ["href", "section", "title", "text"].forEach((keyName) => { + const mappedName = indexFields[keyName]; + if ( + mappedName && + item[mappedName] !== undefined && + mappedName !== keyName + ) { + newItem[keyName] = item[mappedName]; + delete newItem[mappedName]; + } + }); + newItem.text = highlightMatch(query, newItem.text); + return newItem; + }); + }); + return remappedHits; + } + }, + }); +} + +function fuseSearch(query, fuse, fuseOptions) { + return fuse.search(query, fuseOptions).map((result) => { + const addParam = (url, name, value) => { + const anchorParts = url.split("#"); + const baseUrl = anchorParts[0]; + const sep = baseUrl.search("\\?") > 0 ? "&" : "?"; + anchorParts[0] = baseUrl + sep + name + "=" + value; + return anchorParts.join("#"); + }; + + return { + title: result.item.title, + section: result.item.section, + href: addParam(result.item.href, kQueryArg, query), + text: highlightMatch(query, result.item.text), + }; + }); +} diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 00000000..6cfe83ea --- /dev/null +++ b/sitemap.xml @@ -0,0 +1,79 @@ +<?xml version="1.0" encoding="UTF-8"?> +<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9"> + <url> + <loc>https://Nixtla.github.io/hierarchicalforecast/utils.html</loc> + <lastmod>2023-10-03T21:54:51.439Z</lastmod> + </url> + <url> + <loc>https://Nixtla.github.io/hierarchicalforecast/evaluation.html</loc> + <lastmod>2023-10-03T21:54:50.187Z</lastmod> + </url> + <url> + <loc>https://Nixtla.github.io/hierarchicalforecast/examples/mlframeworksexample.html</loc> + <lastmod>2023-10-03T21:54:48.839Z</lastmod> + </url> + <url> + <loc>https://Nixtla.github.io/hierarchicalforecast/examples/installation.html</loc> + <lastmod>2023-10-03T21:54:46.342Z</lastmod> + </url> + <url> + <loc>https://Nixtla.github.io/hierarchicalforecast/examples/index.html</loc> + <lastmod>2023-10-03T21:54:45.138Z</lastmod> + </url> + <url> + <loc>https://Nixtla.github.io/hierarchicalforecast/examples/australiandomestictourism-intervals.html</loc> + <lastmod>2023-10-03T21:54:43.530Z</lastmod> + </url> + <url> + <loc>https://Nixtla.github.io/hierarchicalforecast/examples/nonnegativereconciliation.html</loc> + <lastmod>2023-10-03T21:54:41.438Z</lastmod> + </url> + <url> + <loc>https://Nixtla.github.io/hierarchicalforecast/examples/introduction.html</loc> + <lastmod>2023-10-03T21:54:39.466Z</lastmod> + </url> + <url> + <loc>https://Nixtla.github.io/hierarchicalforecast/examples/tourismlarge-evaluation.html</loc> + <lastmod>2023-10-03T21:54:37.370Z</lastmod> + </url> + <url> + <loc>https://Nixtla.github.io/hierarchicalforecast/methods.html</loc> + <lastmod>2023-10-03T21:54:32.946Z</lastmod> + </url> + <url> + <loc>https://Nixtla.github.io/hierarchicalforecast/probabilistic_methods.html</loc> + <lastmod>2023-10-03T21:54:35.086Z</lastmod> + </url> + <url> + <loc>https://Nixtla.github.io/hierarchicalforecast/examples/australiandomestictourism.html</loc> + <lastmod>2023-10-03T21:54:38.426Z</lastmod> + </url> + <url> + <loc>https://Nixtla.github.io/hierarchicalforecast/examples/australiandomestictourism-bootstraped-intervals.html</loc> + <lastmod>2023-10-03T21:54:40.466Z</lastmod> + </url> + <url> + <loc>https://Nixtla.github.io/hierarchicalforecast/examples/australiandomestictourism-permbu-intervals.html</loc> + <lastmod>2023-10-03T21:54:42.462Z</lastmod> + </url> + <url> + <loc>https://Nixtla.github.io/hierarchicalforecast/examples/hierarchicalforecast-gluonts.html</loc> + <lastmod>2023-10-03T21:54:44.602Z</lastmod> + </url> + <url> + <loc>https://Nixtla.github.io/hierarchicalforecast/examples/tourismsmall.html</loc> + <lastmod>2023-10-03T21:54:45.886Z</lastmod> + </url> + <url> + <loc>https://Nixtla.github.io/hierarchicalforecast/examples/australianprisonpopulation.html</loc> + <lastmod>2023-10-03T21:54:47.235Z</lastmod> + </url> + <url> + <loc>https://Nixtla.github.io/hierarchicalforecast/index.html</loc> + <lastmod>2023-10-03T21:54:49.439Z</lastmod> + </url> + <url> + <loc>https://Nixtla.github.io/hierarchicalforecast/core.html</loc> + <lastmod>2023-10-03T21:54:50.811Z</lastmod> + </url> +</urlset> diff --git a/styles.css b/styles.css new file mode 100644 index 00000000..4be3d9b0 --- /dev/null +++ b/styles.css @@ -0,0 +1,57 @@ +.cell { + margin-bottom: 1rem; +} + +.cell > .sourceCode { + margin-bottom: 0; +} + +.cell-output > pre { + margin-bottom: 0; +} + +.cell-output > pre, .cell-output > .sourceCode > pre, .cell-output-stdout > pre { + margin-left: 0.8rem; + margin-top: 0; + background: none; + border-left: 2px solid lightsalmon; + border-top-left-radius: 0; + border-top-right-radius: 0; +} + +.cell-output > .sourceCode { + border: none; +} + +.cell-output > .sourceCode { + background: none; + margin-top: 0; +} + +div.description { + padding-left: 2px; + padding-top: 5px; + font-style: italic; + font-size: 135%; + opacity: 70%; +} + +/* show_doc signature */ +blockquote > pre { + font-size: 14px; +} + +.table { + font-size: 16px; + /* disable striped tables */ + --bs-table-striped-bg: var(--bs-table-bg); +} + +.quarto-figure-center > figure > figcaption { + text-align: center; +} + +.figure-caption { + font-size: 75%; + font-style: italic; +} \ No newline at end of file diff --git a/utils.html b/utils.html new file mode 100644 index 00000000..7f9630f8 --- /dev/null +++ b/utils.html @@ -0,0 +1,873 @@ +<!DOCTYPE html> +<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en"><head> + +<meta charset="utf-8"> +<meta name="generator" content="quarto-1.3.450"> + +<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes"> + + +<title>hierarchicalforecast - Aggregation/Visualization Utils</title> +<style> +code{white-space: pre-wrap;} +span.smallcaps{font-variant: small-caps;} +div.columns{display: flex; gap: min(4vw, 1.5em);} +div.column{flex: auto; overflow-x: auto;} +div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;} +ul.task-list{list-style: none;} +ul.task-list li input[type="checkbox"] { + width: 0.8em; + margin: 0 0.8em 0.2em -1em; /* quarto-specific, see https://github.com/quarto-dev/quarto-cli/issues/4556 */ + vertical-align: middle; +} +/* CSS for syntax highlighting */ +pre > code.sourceCode { white-space: pre; position: relative; } +pre > code.sourceCode > span { display: inline-block; line-height: 1.25; } +pre > code.sourceCode > span:empty { height: 1.2em; } +.sourceCode { overflow: visible; } +code.sourceCode > span { color: inherit; text-decoration: inherit; } +div.sourceCode { margin: 1em 0; } +pre.sourceCode { margin: 0; } +@media screen { +div.sourceCode { overflow: auto; } +} +@media print { +pre > code.sourceCode { white-space: pre-wrap; } +pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; } +} +pre.numberSource code + { counter-reset: source-line 0; } +pre.numberSource code > span + { position: relative; left: -4em; counter-increment: source-line; } +pre.numberSource code > span > a:first-child::before + { content: counter(source-line); + position: relative; left: -1em; text-align: right; vertical-align: baseline; + border: none; display: inline-block; + -webkit-touch-callout: none; -webkit-user-select: none; + -khtml-user-select: none; -moz-user-select: none; + -ms-user-select: none; user-select: none; + padding: 0 4px; width: 4em; + } +pre.numberSource { margin-left: 3em; padding-left: 4px; } +div.sourceCode + { } +@media screen { +pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; } +} +</style> + + +<script src="site_libs/quarto-nav/quarto-nav.js"></script> +<script src="site_libs/quarto-nav/headroom.min.js"></script> +<script src="site_libs/clipboard/clipboard.min.js"></script> +<script src="site_libs/quarto-search/autocomplete.umd.js"></script> +<script src="site_libs/quarto-search/fuse.min.js"></script> +<script src="site_libs/quarto-search/quarto-search.js"></script> +<meta name="quarto:offset" content="./"> +<link href="./favicon_png.png" rel="icon" type="image/png"> +<script src="site_libs/quarto-html/quarto.js"></script> +<script src="site_libs/quarto-html/popper.min.js"></script> +<script src="site_libs/quarto-html/tippy.umd.min.js"></script> +<script src="site_libs/quarto-html/anchor.min.js"></script> +<link href="site_libs/quarto-html/tippy.css" rel="stylesheet"> +<link href="site_libs/quarto-html/quarto-syntax-highlighting.css" rel="stylesheet" id="quarto-text-highlighting-styles"> +<script src="site_libs/bootstrap/bootstrap.min.js"></script> +<link href="site_libs/bootstrap/bootstrap-icons.css" rel="stylesheet"> +<link href="site_libs/bootstrap/bootstrap.min.css" rel="stylesheet" id="quarto-bootstrap" data-mode="light"> +<script id="quarto-search-options" type="application/json">{ + "location": "navbar", + "copy-button": false, + "collapse-after": 3, + "panel-placement": "end", + "type": "overlay", + "limit": 20, + "language": { + "search-no-results-text": "No results", + "search-matching-documents-text": "matching documents", + "search-copy-link-title": "Copy link to search", + "search-hide-matches-text": "Hide additional matches", + "search-more-match-text": "more match in this document", + "search-more-matches-text": "more matches in this document", + "search-clear-button-title": "Clear", + "search-detached-cancel-button-title": "Cancel", + "search-submit-button-title": "Submit", + "search-label": "Search" + } +}</script> +<script async="" src="https://www.googletagmanager.com/gtag/js?id=G-NXJNCVR18L"></script> + +<script type="text/javascript"> + +window.dataLayer = window.dataLayer || []; +function gtag(){dataLayer.push(arguments);} +gtag('js', new Date()); +gtag('config', 'G-NXJNCVR18L', { 'anonymize_ip': true}); +</script> + + <script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script> + <script src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-chtml-full.js" type="text/javascript"></script> + +<link rel="stylesheet" href="styles.css"> +<meta property="og:title" content="hierarchicalforecast - Aggregation/Visualization Utils"> +<meta property="og:description" content=""> +<meta property="og:site-name" content="hierarchicalforecast"> +<meta name="twitter:title" content="hierarchicalforecast - Aggregation/Visualization Utils"> +<meta name="twitter:description" content=""> +<meta name="twitter:card" content="summary"> +</head> + +<body class="nav-sidebar floating nav-fixed"> + +<div id="quarto-search-results"></div> + <header id="quarto-header" class="headroom fixed-top"> + <nav class="navbar navbar-expand-lg navbar-dark "> + <div class="navbar-container container-fluid"> + <div class="navbar-brand-container"> + <a class="navbar-brand" href="./index.html"> + <span class="navbar-title">hierarchicalforecast</span> + </a> + </div> + <div id="quarto-search" class="" title="Search"></div> + <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + <span class="navbar-toggler-icon"></span> +</button> + <div class="collapse navbar-collapse" id="navbarCollapse"> + <ul class="navbar-nav navbar-nav-scroll me-auto"> + <li class="nav-item"> + <a class="nav-link active" href="./examples/tourismsmall.html" rel="" target="" aria-current="page"> + <span class="menu-text">Get Started</span></a> + </li> + <li class="nav-item dropdown "> + <a class="nav-link dropdown-toggle" href="#" id="nav-menu-nixtlaverse" role="button" data-bs-toggle="dropdown" aria-expanded="false" rel="" target=""> + <span class="menu-text">NixtlaVerse</span> + </a> + <ul class="dropdown-menu" aria-labelledby="nav-menu-nixtlaverse"> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/mlforecast" rel="" target=""> + <span class="dropdown-text">MLForecast š¤</span></a> + </li> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/neuralforecast" rel="" target=""> + <span class="dropdown-text">NeuralForecast š§ </span></a> + </li> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/statsforecast" rel="" target=""> + <span class="dropdown-text">StatsForecast ā”ļø</span></a> + </li> + </ul> + </li> + <li class="nav-item dropdown "> + <a class="nav-link dropdown-toggle" href="#" id="nav-menu-help" role="button" data-bs-toggle="dropdown" aria-expanded="false" rel="" target=""> + <span class="menu-text">Help</span> + </a> + <ul class="dropdown-menu" aria-labelledby="nav-menu-help"> + <li> + <a class="dropdown-item" href="https://github.com/nixtla/hierarchicalforecast/issues/new/choose" rel="" target=""><i class="bi bi-bug" role="img"> +</i> + <span class="dropdown-text">Report an Issue</span></a> + </li> + <li> + <a class="dropdown-item" href="https://join.slack.com/t/nixtlacommunity/shared_invite/zt-1kd5m5db7-7OOfy0xVNf1PcvCiAPWvPw" rel="" target=""><i class="bi bi-chat-right-text" role="img"> +</i> + <span class="dropdown-text">Join our Slack</span></a> + </li> + </ul> + </li> +</ul> + <ul class="navbar-nav navbar-nav-scroll ms-auto"> + <li class="nav-item compact"> + <a class="nav-link" href="https://github.com/nixtla/hierarchicalforecast" rel="" target=""><i class="bi bi-github" role="img"> +</i> + <span class="menu-text"></span></a> + </li> + <li class="nav-item compact"> + <a class="nav-link" href="https://twitter.com/nixtlainc" rel="" target=""><i class="bi bi-twitter" role="img" aria-label="Nixtla Twitter"> +</i> + <span class="menu-text"></span></a> + </li> +</ul> + <div class="quarto-navbar-tools"> +</div> + </div> <!-- /navcollapse --> + </div> <!-- /container-fluid --> + </nav> + <nav class="quarto-secondary-nav"> + <div class="container-fluid d-flex"> + <button type="button" class="quarto-btn-toggle btn" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + <i class="bi bi-layout-text-sidebar-reverse"></i> + </button> + <nav class="quarto-page-breadcrumbs" aria-label="breadcrumb"><ol class="breadcrumb"><li class="breadcrumb-item"><a href="./core.html">API Reference</a></li><li class="breadcrumb-item"><a href="./utils.html">Aggregation/Visualization Utils</a></li></ol></nav> + <a class="flex-grow-1" role="button" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass" aria-controls="quarto-sidebar" aria-expanded="false" aria-label="Toggle sidebar navigation" onclick="if (window.quartoToggleHeadroom) { window.quartoToggleHeadroom(); }"> + </a> + </div> + </nav> +</header> +<!-- content --> +<div id="quarto-content" class="quarto-container page-columns page-rows-contents page-layout-article page-navbar"> +<!-- sidebar --> + <nav id="quarto-sidebar" class="sidebar collapse collapse-horizontal sidebar-navigation floating overflow-auto"> + <div class="sidebar-menu-container"> + <ul class="list-unstyled mt-1"> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./index.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Hierarchical Forecast š</span></a> + </div> +</li> + <li class="px-0"><hr class="sidebar-divider hi "></li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-1" aria-expanded="false"> + <span class="menu-text">Getting Started</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-1" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-1" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/installation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Install</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/tourismsmall.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Reconciliation Quick Start</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/introduction.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Introduction</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-2" aria-expanded="false"> + <span class="menu-text">Tutorials</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-2" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-2" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-3" aria-expanded="false"> + <span class="menu-text">Point Reconciliation</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-3" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-3" class="collapse list-unstyled sidebar-section depth2 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/australiandomestictourism.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Geographical Aggregation (Tourism)</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/australianprisonpopulation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Geographical Aggregation (Prison Population)</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/nonnegativereconciliation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Non-Negative MinTrace</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-4" aria-expanded="false"> + <span class="menu-text">Probabilistic Reconciliation</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-4" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-4" class="collapse list-unstyled sidebar-section depth2 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/australiandomestictourism-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Normality</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/australiandomestictourism-bootstraped-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Bootstrap</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/australiandomestictourism-permbu-intervals.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">PERMBU</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/tourismlarge-evaluation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Probabilistic Forecast Evaluation</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-5" aria-expanded="false"> + <span class="menu-text">ML Forecast Reconciliation</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-5" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-5" class="collapse list-unstyled sidebar-section depth2 "> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/hierarchicalforecast-gluonts.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">GluonTS</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./examples/mlframeworksexample.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Neural/MLForecast</span></a> + </div> +</li> + </ul> + </li> + </ul> + </li> + <li class="sidebar-item"> + <span class="menu-text">Methods</span> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-6" aria-expanded="true"> + <span class="menu-text">API Reference</span></a> + <a class="sidebar-item-toggle text-start" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-6" aria-expanded="true" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-6" class="collapse list-unstyled sidebar-section depth1 show"> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./core.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Core </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./methods.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Reconciliation Methods </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./probabilistic_methods.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text"><span style="color:DarkOrange"> Probabilistic Methods </span></span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./evaluation.html" class="sidebar-item-text sidebar-link"> + <span class="menu-text">Hierarchical Evaluation</span></a> + </div> +</li> + <li class="sidebar-item"> + <div class="sidebar-item-container"> + <a href="./utils.html" class="sidebar-item-text sidebar-link active"> + <span class="menu-text">Aggregation/Visualization Utils</span></a> + </div> +</li> + </ul> + </li> + <li class="sidebar-item sidebar-item-section"> + <div class="sidebar-item-container"> + <a class="sidebar-item-text sidebar-link text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-7" aria-expanded="false"> + <span class="menu-text">Community</span></a> + <a class="sidebar-item-toggle text-start collapsed" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar-section-7" aria-expanded="false" aria-label="Toggle section"> + <i class="bi bi-chevron-right ms-2"></i> + </a> + </div> + <ul id="quarto-sidebar-section-7" class="collapse list-unstyled sidebar-section depth1 "> + <li class="sidebar-item"> + <span class="menu-text">Contributing</span> + </li> + </ul> + </li> + </ul> + </div> +</nav> +<div id="quarto-sidebar-glass" data-bs-toggle="collapse" data-bs-target="#quarto-sidebar,#quarto-sidebar-glass"></div> +<!-- margin-sidebar --> + <div id="quarto-margin-sidebar" class="sidebar margin-sidebar"> + <nav id="TOC" role="doc-toc" class="toc-active"> + <h2 id="toc-title">On this page</h2> + + <ul> + <li><a href="#aggregate-function" id="toc-aggregate-function" class="nav-link active" data-scroll-target="#aggregate-function"><span style="color:DarkBlue"> Aggregate Function </span></a> + <ul class="collapse"> + <li><a href="#aggregate" id="toc-aggregate" class="nav-link" data-scroll-target="#aggregate">aggregate</a></li> + </ul></li> + <li><a href="#hierarchical-visualization" id="toc-hierarchical-visualization" class="nav-link" data-scroll-target="#hierarchical-visualization"><span style="color:DarkBlue"> Hierarchical Visualization </span></a> + <ul class="collapse"> + <li><a href="#hierarchicalplot" id="toc-hierarchicalplot" class="nav-link" data-scroll-target="#hierarchicalplot">HierarchicalPlot</a></li> + <li><a href="#plot_summing_matrix" id="toc-plot_summing_matrix" class="nav-link" data-scroll-target="#plot_summing_matrix">plot_summing_matrix</a></li> + <li><a href="#plot_series" id="toc-plot_series" class="nav-link" data-scroll-target="#plot_series">plot_series</a></li> + <li><a href="#plot_hierarchically_linked_series" id="toc-plot_hierarchically_linked_series" class="nav-link" data-scroll-target="#plot_hierarchically_linked_series">plot_hierarchically_linked_series</a></li> + <li><a href="#plot_hierarchical_predictions_gap" id="toc-plot_hierarchical_predictions_gap" class="nav-link" data-scroll-target="#plot_hierarchical_predictions_gap">plot_hierarchical_predictions_gap</a></li> + </ul></li> + <li><a href="#external-forecast-adapters" id="toc-external-forecast-adapters" class="nav-link" data-scroll-target="#external-forecast-adapters"><span style="color:DarkBlue"> External Forecast Adapters </span></a> + <ul class="collapse"> + <li><a href="#samples_to_quantiles_df" id="toc-samples_to_quantiles_df" class="nav-link" data-scroll-target="#samples_to_quantiles_df">samples_to_quantiles_df</a></li> + </ul></li> + </ul> +<div class="toc-actions"><div><i class="bi bi-github"></i></div><div class="action-links"><p><a href="https://github.com/Nixtla/hierarchicalforecast/issues/new" class="toc-action">Report an issue</a></p></div></div></nav> + </div> +<!-- main --> +<main class="content" id="quarto-document-content"> + +<header id="title-block-header" class="quarto-title-block default"> +<div class="quarto-title"> +<h1 class="title">Aggregation/Visualization Utils</h1> +</div> + + + +<div class="quarto-title-meta"> + + + + + </div> + + +</header> + +<!-- WARNING: THIS FILE WAS AUTOGENERATED! DO NOT EDIT! --> +<p>The <code>HierarchicalForecast</code> package contains utility functions to wrangle and visualize hierarchical series datasets. The <a href="https://Nixtla.github.io/hierarchicalforecast/utils.html#aggregate"><code>aggregate</code></a> function of the module allows you to create a hierarchy from categorical variables representing the structure levels, returning also the aggregation contraints matrix <span class="math inline">\(\mathbf{S}\)</span>.</p> +<p>In addition, <code>HierarchicalForecast</code> ensures compatibility of its reconciliation methods with other popular machine-learning libraries via its external forecast adapters that transform output base forecasts from external libraries into a compatible data frame format.</p> +<section id="aggregate-function" class="level1"> +<h1><span style="color:DarkBlue"> Aggregate Function </span></h1> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/utils.py#L154" target="_blank" style="float:right; font-size:smaller">source</a></p> +<section id="aggregate" class="level3"> +<h3 class="anchored" data-anchor-id="aggregate">aggregate</h3> +<blockquote class="blockquote"> +<pre><code> aggregate (df:pandas.core.frame.DataFrame, spec:List[List[str]], + is_balanced:bool=False, sparse_s:bool=False)</code></pre> +</blockquote> +<p>Utils Aggregation Function. Aggregates bottom level series contained in the pandas DataFrame <code>df</code> according to levels defined in the <code>spec</code> list.</p> +<table class="table"> +<colgroup> +<col style="width: 6%"> +<col style="width: 25%"> +<col style="width: 34%"> +<col style="width: 34%"> +</colgroup> +<thead> +<tr class="header"> +<th></th> +<th><strong>Type</strong></th> +<th><strong>Default</strong></th> +<th><strong>Details</strong></th> +</tr> +</thead> +<tbody> +<tr class="odd"> +<td>df</td> +<td>DataFrame</td> +<td></td> +<td>Dataframe with columns <code>['ds', 'y']</code> and columns to aggregate.</td> +</tr> +<tr class="even"> +<td>spec</td> +<td>typing.List[typing.List[str]]</td> +<td></td> +<td>List of levels. Each element of the list should contain a list of columns of <code>df</code> to aggregate.</td> +</tr> +<tr class="odd"> +<td>is_balanced</td> +<td>bool</td> +<td>False</td> +<td>Deprecated.</td> +</tr> +<tr class="even"> +<td>sparse_s</td> +<td>bool</td> +<td>False</td> +<td>Return <code>S_df</code> as a sparse dataframe.</td> +</tr> +<tr class="odd"> +<td><strong>Returns</strong></td> +<td><strong>pandas DataFrame</strong></td> +<td></td> +<td><strong>Hierarchically structured series.</strong></td> +</tr> +</tbody> +</table> +</section> +</section> +<section id="hierarchical-visualization" class="level1"> +<h1><span style="color:DarkBlue"> Hierarchical Visualization </span></h1> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/utils.py#L231" target="_blank" style="float:right; font-size:smaller">source</a></p> +<section id="hierarchicalplot" class="level3"> +<h3 class="anchored" data-anchor-id="hierarchicalplot">HierarchicalPlot</h3> +<blockquote class="blockquote"> +<pre><code> HierarchicalPlot (S:pandas.core.frame.DataFrame, + tags:Dict[str,numpy.ndarray])</code></pre> +</blockquote> +<p>Hierarchical Plot</p> +<p>This class contains a collection of matplotlib visualization methods, suited for small to medium sized hierarchical series.</p> +<p><strong>Parameters:</strong><br> <code>S</code>: pd.DataFrame with summing matrix of size <code>(base, bottom)</code>, see <a href="https://nixtla.github.io/hierarchicalforecast/utils.html#aggregate">aggregate function</a>.<br> <code>tags</code>: np.ndarray, with hierarchical aggregation indexes, where each key is a level and its value contains tags associated to that level.<br><br></p> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/utils.py#L248" target="_blank" style="float:right; font-size:smaller">source</a></p> +</section> +<section id="plot_summing_matrix" class="level3"> +<h3 class="anchored" data-anchor-id="plot_summing_matrix">plot_summing_matrix</h3> +<blockquote class="blockquote"> +<pre><code> plot_summing_matrix ()</code></pre> +</blockquote> +<p>Summation Constraints plot</p> +<p>This method simply plots the hierarchical aggregation constraints matrix <span class="math inline">\(\mathbf{S}\)</span>.</p> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/utils.py#L259" target="_blank" style="float:right; font-size:smaller">source</a></p> +</section> +<section id="plot_series" class="level3"> +<h3 class="anchored" data-anchor-id="plot_series">plot_series</h3> +<blockquote class="blockquote"> +<pre><code> plot_series (series:str, Y_df:Optional[pandas.core.frame.DataFrame]=None, + models:Optional[List[str]]=None, + level:Optional[List[int]]=None)</code></pre> +</blockquote> +<p>Single Series plot</p> +<p><strong>Parameters:</strong><br> <code>series</code>: str, string identifying the <code>'unique_id'</code> any-level series to plot.<br> <code>Y_df</code>: pd.DataFrame, hierarchically structured series (<span class="math inline">\(\mathbf{y}_{[a,b]}\)</span>). It contains columns <code>['unique_id', 'ds', 'y']</code>, it may have <code>'models'</code>.<br> <code>models</code>: List[str], string identifying filtering model columns. <code>level</code>: float list 0-100, confidence levels for prediction intervals available in <code>Y_df</code>.<br></p> +<p><strong>Returns:</strong><br> Single series plot with filtered models and prediction interval level.<br><br></p> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/utils.py#L311" target="_blank" style="float:right; font-size:smaller">source</a></p> +</section> +<section id="plot_hierarchically_linked_series" class="level3"> +<h3 class="anchored" data-anchor-id="plot_hierarchically_linked_series">plot_hierarchically_linked_series</h3> +<blockquote class="blockquote"> +<pre><code> plot_hierarchically_linked_series (bottom_series:str, + Y_df:Optional[pandas.core.frame.DataFr + ame]=None, + models:Optional[List[str]]=None, + level:Optional[List[int]]=None)</code></pre> +</blockquote> +<p>Hierarchically Linked Series plot</p> +<p><strong>Parameters:</strong><br> <code>bottom_series</code>: str, string identifying the <code>'unique_id'</code> bottom-level series to plot.<br> <code>Y_df</code>: pd.DataFrame, hierarchically structured series (<span class="math inline">\(\mathbf{y}_{[a,b]}\)</span>). It contains columns [āunique_idā, ādsā, āyā] and models. <br> <code>models</code>: List[str], string identifying filtering model columns. <code>level</code>: float list 0-100, confidence levels for prediction intervals available in <code>Y_df</code>.<br></p> +<p><strong>Returns:</strong><br> Collection of hierarchilly linked series plots associated with the <code>bottom_series</code> and filtered models and prediction interval level.<br><br></p> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/utils.py#L374" target="_blank" style="float:right; font-size:smaller">source</a></p> +</section> +<section id="plot_hierarchical_predictions_gap" class="level3"> +<h3 class="anchored" data-anchor-id="plot_hierarchical_predictions_gap">plot_hierarchical_predictions_gap</h3> +<blockquote class="blockquote"> +<pre><code> plot_hierarchical_predictions_gap (Y_df:pandas.core.frame.DataFrame, + models:Optional[List[str]]=None, + xlabel:Optional=None, + ylabel:Optional=None)</code></pre> +</blockquote> +<p>Hierarchically Predictions Gap plot</p> +<p><strong>Parameters:</strong><br> <code>Y_df</code>: pd.DataFrame, hierarchically structured series (<span class="math inline">\(\mathbf{y}_{[a,b]}\)</span>). It contains columns [āunique_idā, ādsā, āyā] and models. <br> <code>models</code>: List[str], string identifying filtering model columns. <code>xlabel</code>: str, string for the plotās x axis label. <code>ylable</code>: str, string for the plotās y axis label.</p> +<p><strong>Returns:</strong><br> Plots of aggregated predictions at different levels of the hierarchical structure. The aggregation is performed according to the tag levels see <a href="https://nixtla.github.io/hierarchicalforecast/utils.html">aggregate function</a>.<br><br></p> +<div class="cell"> +<div class="sourceCode cell-code" id="cb7"><pre class="sourceCode python code-with-copy"><code class="sourceCode python"><span id="cb7-1"><a href="#cb7-1" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> statsforecast.core <span class="im">import</span> StatsForecast</span> +<span id="cb7-2"><a href="#cb7-2" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> statsforecast.models <span class="im">import</span> AutoARIMA, ETS, Naive</span> +<span id="cb7-3"><a href="#cb7-3" aria-hidden="true" tabindex="-1"></a><span class="im">from</span> datasetsforecast.hierarchical <span class="im">import</span> HierarchicalData</span> +<span id="cb7-4"><a href="#cb7-4" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb7-5"><a href="#cb7-5" aria-hidden="true" tabindex="-1"></a>Y_df, S, tags <span class="op">=</span> HierarchicalData.load(<span class="st">'./data'</span>, <span class="st">'Labour'</span>)</span> +<span id="cb7-6"><a href="#cb7-6" aria-hidden="true" tabindex="-1"></a>Y_df[<span class="st">'ds'</span>] <span class="op">=</span> pd.to_datetime(Y_df[<span class="st">'ds'</span>])</span> +<span id="cb7-7"><a href="#cb7-7" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb7-8"><a href="#cb7-8" aria-hidden="true" tabindex="-1"></a>Y_test_df <span class="op">=</span> Y_df.groupby(<span class="st">'unique_id'</span>).tail(<span class="dv">24</span>)</span> +<span id="cb7-9"><a href="#cb7-9" aria-hidden="true" tabindex="-1"></a>Y_train_df <span class="op">=</span> Y_df.drop(Y_test_df.index)</span> +<span id="cb7-10"><a href="#cb7-10" aria-hidden="true" tabindex="-1"></a>Y_test_df <span class="op">=</span> Y_test_df.set_index(<span class="st">'unique_id'</span>)</span> +<span id="cb7-11"><a href="#cb7-11" aria-hidden="true" tabindex="-1"></a>Y_train_df <span class="op">=</span> Y_train_df.set_index(<span class="st">'unique_id'</span>)</span> +<span id="cb7-12"><a href="#cb7-12" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb7-13"><a href="#cb7-13" aria-hidden="true" tabindex="-1"></a>fcst <span class="op">=</span> StatsForecast(</span> +<span id="cb7-14"><a href="#cb7-14" aria-hidden="true" tabindex="-1"></a> df<span class="op">=</span>Y_train_df, </span> +<span id="cb7-15"><a href="#cb7-15" aria-hidden="true" tabindex="-1"></a> <span class="co">#models=[AutoARIMA(season_length=12), Naive()], </span></span> +<span id="cb7-16"><a href="#cb7-16" aria-hidden="true" tabindex="-1"></a> models<span class="op">=</span>[ETS(season_length<span class="op">=</span><span class="dv">12</span>, model<span class="op">=</span><span class="st">'AAZ'</span>)],</span> +<span id="cb7-17"><a href="#cb7-17" aria-hidden="true" tabindex="-1"></a> freq<span class="op">=</span><span class="st">'MS'</span>, </span> +<span id="cb7-18"><a href="#cb7-18" aria-hidden="true" tabindex="-1"></a> n_jobs<span class="op">=-</span><span class="dv">1</span></span> +<span id="cb7-19"><a href="#cb7-19" aria-hidden="true" tabindex="-1"></a>)</span> +<span id="cb7-20"><a href="#cb7-20" aria-hidden="true" tabindex="-1"></a>Y_hat_df <span class="op">=</span> fcst.forecast(h<span class="op">=</span><span class="dv">24</span>)</span> +<span id="cb7-21"><a href="#cb7-21" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb7-22"><a href="#cb7-22" aria-hidden="true" tabindex="-1"></a><span class="co"># Plot prediction difference of different aggregation</span></span> +<span id="cb7-23"><a href="#cb7-23" aria-hidden="true" tabindex="-1"></a><span class="co"># Levels Country, Country/Region, Country/Gender/Region ...</span></span> +<span id="cb7-24"><a href="#cb7-24" aria-hidden="true" tabindex="-1"></a>hplots <span class="op">=</span> HierarchicalPlot(S<span class="op">=</span>S, tags<span class="op">=</span>tags)</span> +<span id="cb7-25"><a href="#cb7-25" aria-hidden="true" tabindex="-1"></a></span> +<span id="cb7-26"><a href="#cb7-26" aria-hidden="true" tabindex="-1"></a>hplots.plot_hierarchical_predictions_gap(</span> +<span id="cb7-27"><a href="#cb7-27" aria-hidden="true" tabindex="-1"></a> Y_df<span class="op">=</span>Y_hat_df, models<span class="op">=</span><span class="st">'ETS'</span>,</span> +<span id="cb7-28"><a href="#cb7-28" aria-hidden="true" tabindex="-1"></a> xlabel<span class="op">=</span><span class="st">'Month'</span>, ylabel<span class="op">=</span><span class="st">'Predictions'</span>,</span> +<span id="cb7-29"><a href="#cb7-29" aria-hidden="true" tabindex="-1"></a>)</span></code><button title="Copy to Clipboard" class="code-copy-button"><i class="bi"></i></button></pre></div> +</div> +</section> +</section> +<section id="external-forecast-adapters" class="level1"> +<h1><span style="color:DarkBlue"> External Forecast Adapters </span></h1> +<hr> +<p><a href="https://github.com/Nixtla/hierarchicalforecast/blob/main/hierarchicalforecast/utils.py#L471" target="_blank" style="float:right; font-size:smaller">source</a></p> +<section id="samples_to_quantiles_df" class="level3"> +<h3 class="anchored" data-anchor-id="samples_to_quantiles_df">samples_to_quantiles_df</h3> +<blockquote class="blockquote"> +<pre><code> samples_to_quantiles_df (samples:numpy.ndarray, unique_ids:Iterable[str], + dates:Iterable, + quantiles:Optional[Iterable[float]]=None, + level:Optional[Iterable[int]]=None, + model_name:Optional[str]='model')</code></pre> +</blockquote> +<p>Transform Random Samples into HierarchicalForecast input. Auxiliary function to create compatible HierarchicalForecast input <code>Y_hat_df</code> dataframe.</p> +<p><strong>Parameters:</strong><br> <code>samples</code>: numpy array. Samples from forecast distribution of shape [n_series, n_samples, horizon].<br> <code>unique_ids</code>: string list. Unique identifiers for each time series.<br> <code>dates</code>: datetime list. List of forecast dates.<br> <code>quantiles</code>: float list in [0., 1.]. Alternative to level, quantiles to estimate from y distribution.<br> <code>level</code>: int list in [0,100]. Probability levels for prediction intervals.<br> <code>model_name</code>: string. Name of forecasting model.<br></p> +<p><strong>Returns:</strong><br> <code>quantiles</code>: float list in [0., 1.]. quantiles to estimate from y distribution .<br> <code>Y_hat_df</code>: pd.DataFrame. With base quantile forecasts with columns ds and models to reconcile indexed by unique_id.</p> + + +</section> +</section> + +<p>If you find the code useful, please ā us on <a href="https://github.com/nixtla/hierarchicalforecast">Github</a></p></main> <!-- /main --> +<script id="quarto-html-after-body" type="application/javascript"> +window.document.addEventListener("DOMContentLoaded", function (event) { + const toggleBodyColorMode = (bsSheetEl) => { + const mode = bsSheetEl.getAttribute("data-mode"); + const bodyEl = window.document.querySelector("body"); + if (mode === "dark") { + bodyEl.classList.add("quarto-dark"); + bodyEl.classList.remove("quarto-light"); + } else { + bodyEl.classList.add("quarto-light"); + bodyEl.classList.remove("quarto-dark"); + } + } + const toggleBodyColorPrimary = () => { + const bsSheetEl = window.document.querySelector("link#quarto-bootstrap"); + if (bsSheetEl) { + toggleBodyColorMode(bsSheetEl); + } + } + toggleBodyColorPrimary(); + const icon = "ī§"; + const anchorJS = new window.AnchorJS(); + anchorJS.options = { + placement: 'right', + icon: icon + }; + anchorJS.add('.anchored'); + const isCodeAnnotation = (el) => { + for (const clz of el.classList) { + if (clz.startsWith('code-annotation-')) { + return true; + } + } + return false; + } + const clipboard = new window.ClipboardJS('.code-copy-button', { + text: function(trigger) { + const codeEl = trigger.previousElementSibling.cloneNode(true); + for (const childEl of codeEl.children) { + if (isCodeAnnotation(childEl)) { + childEl.remove(); + } + } + return codeEl.innerText; + } + }); + clipboard.on('success', function(e) { + // button target + const button = e.trigger; + // don't keep focus + button.blur(); + // flash "checked" + button.classList.add('code-copy-button-checked'); + var currentTitle = button.getAttribute("title"); + button.setAttribute("title", "Copied!"); + let tooltip; + if (window.bootstrap) { + button.setAttribute("data-bs-toggle", "tooltip"); + button.setAttribute("data-bs-placement", "left"); + button.setAttribute("data-bs-title", "Copied!"); + tooltip = new bootstrap.Tooltip(button, + { trigger: "manual", + customClass: "code-copy-button-tooltip", + offset: [0, -8]}); + tooltip.show(); + } + setTimeout(function() { + if (tooltip) { + tooltip.hide(); + button.removeAttribute("data-bs-title"); + button.removeAttribute("data-bs-toggle"); + button.removeAttribute("data-bs-placement"); + } + button.setAttribute("title", currentTitle); + button.classList.remove('code-copy-button-checked'); + }, 1000); + // clear code selection + e.clearSelection(); + }); + function tippyHover(el, contentFn) { + const config = { + allowHTML: true, + content: contentFn, + maxWidth: 500, + delay: 100, + arrow: false, + appendTo: function(el) { + return el.parentElement; + }, + interactive: true, + interactiveBorder: 10, + theme: 'quarto', + placement: 'bottom-start' + }; + window.tippy(el, config); + } + const noterefs = window.document.querySelectorAll('a[role="doc-noteref"]'); + for (var i=0; i<noterefs.length; i++) { + const ref = noterefs[i]; + tippyHover(ref, function() { + // use id or data attribute instead here + let href = ref.getAttribute('data-footnote-href') || ref.getAttribute('href'); + try { href = new URL(href).hash; } catch {} + const id = href.replace(/^#\/?/, ""); + const note = window.document.getElementById(id); + return note.innerHTML; + }); + } + let selectedAnnoteEl; + const selectorForAnnotation = ( cell, annotation) => { + let cellAttr = 'data-code-cell="' + cell + '"'; + let lineAttr = 'data-code-annotation="' + annotation + '"'; + const selector = 'span[' + cellAttr + '][' + lineAttr + ']'; + return selector; + } + const selectCodeLines = (annoteEl) => { + const doc = window.document; + const targetCell = annoteEl.getAttribute("data-target-cell"); + const targetAnnotation = annoteEl.getAttribute("data-target-annotation"); + const annoteSpan = window.document.querySelector(selectorForAnnotation(targetCell, targetAnnotation)); + const lines = annoteSpan.getAttribute("data-code-lines").split(","); + const lineIds = lines.map((line) => { + return targetCell + "-" + line; + }) + let top = null; + let height = null; + let parent = null; + if (lineIds.length > 0) { + //compute the position of the single el (top and bottom and make a div) + const el = window.document.getElementById(lineIds[0]); + top = el.offsetTop; + height = el.offsetHeight; + parent = el.parentElement.parentElement; + if (lineIds.length > 1) { + const lastEl = window.document.getElementById(lineIds[lineIds.length - 1]); + const bottom = lastEl.offsetTop + lastEl.offsetHeight; + height = bottom - top; + } + if (top !== null && height !== null && parent !== null) { + // cook up a div (if necessary) and position it + let div = window.document.getElementById("code-annotation-line-highlight"); + if (div === null) { + div = window.document.createElement("div"); + div.setAttribute("id", "code-annotation-line-highlight"); + div.style.position = 'absolute'; + parent.appendChild(div); + } + div.style.top = top - 2 + "px"; + div.style.height = height + 4 + "px"; + let gutterDiv = window.document.getElementById("code-annotation-line-highlight-gutter"); + if (gutterDiv === null) { + gutterDiv = window.document.createElement("div"); + gutterDiv.setAttribute("id", "code-annotation-line-highlight-gutter"); + gutterDiv.style.position = 'absolute'; + const codeCell = window.document.getElementById(targetCell); + const gutter = codeCell.querySelector('.code-annotation-gutter'); + gutter.appendChild(gutterDiv); + } + gutterDiv.style.top = top - 2 + "px"; + gutterDiv.style.height = height + 4 + "px"; + } + selectedAnnoteEl = annoteEl; + } + }; + const unselectCodeLines = () => { + const elementsIds = ["code-annotation-line-highlight", "code-annotation-line-highlight-gutter"]; + elementsIds.forEach((elId) => { + const div = window.document.getElementById(elId); + if (div) { + div.remove(); + } + }); + selectedAnnoteEl = undefined; + }; + // Attach click handler to the DT + const annoteDls = window.document.querySelectorAll('dt[data-target-cell]'); + for (const annoteDlNode of annoteDls) { + annoteDlNode.addEventListener('click', (event) => { + const clickedEl = event.target; + if (clickedEl !== selectedAnnoteEl) { + unselectCodeLines(); + const activeEl = window.document.querySelector('dt[data-target-cell].code-annotation-active'); + if (activeEl) { + activeEl.classList.remove('code-annotation-active'); + } + selectCodeLines(clickedEl); + clickedEl.classList.add('code-annotation-active'); + } else { + // Unselect the line + unselectCodeLines(); + clickedEl.classList.remove('code-annotation-active'); + } + }); + } + const findCites = (el) => { + const parentEl = el.parentElement; + if (parentEl) { + const cites = parentEl.dataset.cites; + if (cites) { + return { + el, + cites: cites.split(' ') + }; + } else { + return findCites(el.parentElement) + } + } else { + return undefined; + } + }; + var bibliorefs = window.document.querySelectorAll('a[role="doc-biblioref"]'); + for (var i=0; i<bibliorefs.length; i++) { + const ref = bibliorefs[i]; + const citeInfo = findCites(ref); + if (citeInfo) { + tippyHover(citeInfo.el, function() { + var popup = window.document.createElement('div'); + citeInfo.cites.forEach(function(cite) { + var citeDiv = window.document.createElement('div'); + citeDiv.classList.add('hanging-indent'); + citeDiv.classList.add('csl-entry'); + var biblioDiv = window.document.getElementById('ref-' + cite); + if (biblioDiv) { + citeDiv.innerHTML = biblioDiv.innerHTML; + } + popup.appendChild(citeDiv); + }); + return popup.innerHTML; + }); + } + } +}); +</script> +</div> <!-- /content --> + + + +</body></html> \ No newline at end of file