| { | |
| "cells": [ | |
| { | |
| "cell_type": "markdown", | |
| "id": "7fb27b941602401d91542211134fc71a", | |
| "metadata": {}, | |
| "source": [ | |
| "Licensed to the Apache Software Foundation (ASF) under one\nor more contributor license agreements. See the NOTICE file\ndistributed with this work for additional information\nregarding copyright ownership. The ASF licenses this file\nto you under the Apache License, Version 2.0 (the\n\"License\"); you may not use this file except in compliance\nwith the License. You may obtain a copy of the License at\n\n http://www.apache.org/licenses/LICENSE-2.0\n\nUnless required by applicable law or agreed to in writing,\nsoftware distributed under the License is distributed on an\n\"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\nKIND, either express or implied. See the License for the\nspecific language governing permissions and limitations\nunder the License." | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "id": "f21e8882", | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "# Execute this cell to install dependencies\n", | |
| "%pip install apache-hamilton[visualization] pandas scipy seaborn matplotlib" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "id": "5b2f7a6c", | |
| "metadata": {}, | |
| "source": [ | |
| "# Modeling due date probabilities [](https://colab.research.google.com/github/dagworks-inc/hamilton/blob/main/examples/due_date_probabilities/notebook.ipynb) [](https://github.com/apache/hamilton/blob/main/examples/due_date_probabilities/notebook.ipynb)\n", | |
| "\n", | |
| "\n", | |
| "In this notebook we model the probability of going into labor, given the start date of a pregnancy. We do a few things:\n", | |
| "\n", | |
| "1. [Create some tools to make calendar visualization easier](#date_viz)\n", | |
| "2. [Set up some constants](#constants)\n", | |
| "3. [Compute base date calculations](#base_dates)\n", | |
| "4. [Compute probability distributions](#distributions)\n", | |
| "5. [Plot some analysis](#analysis)\n", | |
| "6. [Show how we derived the parameters in 5](#modeling) as a bonus\n", | |
| "\n", | |
| "You can follow along [here](https://colab.research.google.com/github/DAGWorks-Inc/hamilton/blob/main/examples/due_date_probabilities/notebook.ipynb) if you want to run in google collab." | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": null, | |
| "id": "59db9c9a", | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "%load_ext hamilton.plugins.jupyter_magic" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "id": "68022884", | |
| "metadata": {}, | |
| "source": [ | |
| "<a id='date_viz'/>\n", | |
| "\n", | |
| "# Utilities for date viz\n", | |
| "\n", | |
| "This just sets up functions to display a calendar. We'll be able to see the dates that our system produces. \n", | |
| "This uses the builtin [calendar](https://docs.python.org/3/library/calendar.html) module, and draws from \n", | |
| "this [recipe](https://gist.github.com/flutefreak7/53f7b36baaa122cfbfe18ebf83b6f0e3).\n", | |
| "\n", | |
| "We add a few more capabilities -- enabling us to view a date with a colored \"scale\". This is not particularly important, but it does make this\n", | |
| "more fun." | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 26, | |
| "id": "f0224f8f", | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "import datetime\n", | |
| "from calendar import HTMLCalendar\n", | |
| "\n", | |
| "import pandas as pd\n", | |
| "from IPython.display import HTML, display_html\n", | |
| "\n", | |
| "\n", | |
| "class HighlightedCalendar(HTMLCalendar):\n", | |
| " def __init__(\n", | |
| " self, highlight: list | None = None, normalized_scale: list | None = None, *args, **kwargs\n", | |
| " ):\n", | |
| " super().__init__(*args, **kwargs)\n", | |
| " self._highlight = highlight or []\n", | |
| " self._normalized_scale = normalized_scale or []\n", | |
| "\n", | |
| " def formatday(self, day, weekday):\n", | |
| " \"\"\"\n", | |
| " Return a day as a table cell.\n", | |
| " \"\"\"\n", | |
| " if day in self._highlight:\n", | |
| " index = self._highlight.index(day)\n", | |
| " if len(self._normalized_scale) > 0:\n", | |
| " alpha = self._normalized_scale[index] * 0.3\n", | |
| " else:\n", | |
| " alpha = 0.3\n", | |
| " return f'<td class=\"{self.cssclasses[weekday]}\" style=\"background-color:rgba(227, 30, 48, {alpha});\">{day}</td>'\n", | |
| " else:\n", | |
| " return super().formatday(day, weekday)\n", | |
| "\n", | |
| "\n", | |
| "def view_date_range(date_range: pd.Series, scale: pd.Series = None):\n", | |
| " # normalize\n", | |
| " if scale is not None:\n", | |
| " max_scale = max(scale)\n", | |
| " min_scale = min(scale)\n", | |
| " scale = min_scale + (scale - min_scale) / max_scale\n", | |
| " else:\n", | |
| " scale = 1\n", | |
| " html = \"<table><tr>\"\n", | |
| " month_year_combos = {(date.year, date.month) for date in date_range}\n", | |
| " combined_df = pd.DataFrame(dict(dates=date_range, scale=scale))\n", | |
| " for year, month in month_year_combos:\n", | |
| " filtered_df = combined_df[\n", | |
| " (combined_df.dates.dt.year == year) & (combined_df.dates.dt.month == month)\n", | |
| " ]\n", | |
| " cal = HighlightedCalendar(\n", | |
| " highlight=list([item.day for item in filtered_df.dates]),\n", | |
| " normalized_scale=list(filtered_df.scale),\n", | |
| " )\n", | |
| " html += f\"<td>{cal.formatmonth(year, month)}</td>\"\n", | |
| "\n", | |
| " html += \"</tr></table>\"\n", | |
| " display_html(HTML(html))" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "id": "de233662", | |
| "metadata": {}, | |
| "source": [ | |
| "<a id='constants'></a>\n", | |
| "\n", | |
| "# Constants\n", | |
| "These are constants we'll use (largely dates) for the rest of the notebook.\n", | |
| "Change to be yours." | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 27, | |
| "id": "ba067ca8", | |
| "metadata": {}, | |
| "outputs": [], | |
| "source": [ | |
| "# Start date of the pregnancy (first of the last period)\n", | |
| "PREGNANCY_START_DATE = datetime.datetime.strptime(\"20231012\", \"%Y%m%d\")\n", | |
| "\n", | |
| "# Today -- set to the past if you don't want a true conditional probability\n", | |
| "# TODAY = datetime.datetime.today()\n", | |
| "TODAY = datetime.datetime.strptime(\"20240713\", \"%Y%m%d\")" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "id": "c2bbca95", | |
| "metadata": {}, | |
| "source": [ | |
| "<a id='base_dates'></a>\n", | |
| "\n", | |
| "# Computing dates\n", | |
| "\n", | |
| "This is a hamilton module that computes date range. In the first cell, we define two functions. In the next cell, we instantiate it in a driver,\n", | |
| "and visualize the possible dates. These are just the date ranges we care about, we'll compute the *probable* dates later." | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 28, | |
| "id": "dc06c15d", | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "data": { | |
| "image/svg+xml": [ | |
| "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n", | |
| "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n", | |
| " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n", | |
| "<!-- Generated by graphviz version 12.0.0 (20240704.0754)\n", | |
| " -->\n", | |
| "<!-- Pages: 1 -->\n", | |
| "<svg width=\"527pt\" height=\"211pt\"\n", | |
| " viewBox=\"0.00 0.00 526.80 210.80\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n", | |
| "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 206.8)\">\n", | |
| "<polygon fill=\"white\" stroke=\"none\" points=\"-4,4 -4,-206.8 522.8,-206.8 522.8,4 -4,4\"/>\n", | |
| "<g id=\"clust1\" class=\"cluster\">\n", | |
| "<title>cluster__legend</title>\n", | |
| "<polygon fill=\"#ffffff\" stroke=\"black\" points=\"31.62,-64.8 31.62,-194.8 116.47,-194.8 116.47,-64.8 31.62,-64.8\"/>\n", | |
| "<text text-anchor=\"middle\" x=\"74.05\" y=\"-177.5\" font-family=\"Helvetica,sans-Serif\" font-size=\"14.00\">Legend</text>\n", | |
| "</g>\n", | |
| "<!-- due_date -->\n", | |
| "<g id=\"node1\" class=\"node\">\n", | |
| "<title>due_date</title>\n", | |
| "<path fill=\"#b4d8e4\" stroke=\"black\" d=\"M302.32,-63.6C302.32,-63.6 245.47,-63.6 245.47,-63.6 239.47,-63.6 233.47,-57.6 233.47,-51.6 233.47,-51.6 233.47,-12 233.47,-12 233.47,-6 239.47,0 245.47,0 245.47,0 302.32,0 302.32,0 308.32,0 314.32,-6 314.32,-12 314.32,-12 314.32,-51.6 314.32,-51.6 314.32,-57.6 308.32,-63.6 302.32,-63.6\"/>\n", | |
| "<text text-anchor=\"start\" x=\"244.27\" y=\"-40.5\" font-family=\"Helvetica,sans-Serif\" font-weight=\"bold\" font-size=\"14.00\">due_date</text>\n", | |
| "<text text-anchor=\"start\" x=\"247.65\" y=\"-12.5\" font-family=\"Helvetica,sans-Serif\" font-style=\"italic\" font-size=\"14.00\">datetime</text>\n", | |
| "</g>\n", | |
| "<!-- possible_dates -->\n", | |
| "<g id=\"node2\" class=\"node\">\n", | |
| "<title>possible_dates</title>\n", | |
| "<path fill=\"#b4d8e4\" stroke=\"black\" d=\"M506.8,-104.6C506.8,-104.6 411.7,-104.6 411.7,-104.6 405.7,-104.6 399.7,-98.6 399.7,-92.6 399.7,-92.6 399.7,-53 399.7,-53 399.7,-47 405.7,-41 411.7,-41 411.7,-41 506.8,-41 506.8,-41 512.8,-41 518.8,-47 518.8,-53 518.8,-53 518.8,-92.6 518.8,-92.6 518.8,-98.6 512.8,-104.6 506.8,-104.6\"/>\n", | |
| "<text text-anchor=\"start\" x=\"410.5\" y=\"-81.5\" font-family=\"Helvetica,sans-Serif\" font-weight=\"bold\" font-size=\"14.00\">possible_dates</text>\n", | |
| "<text text-anchor=\"start\" x=\"440.12\" y=\"-53.5\" font-family=\"Helvetica,sans-Serif\" font-style=\"italic\" font-size=\"14.00\">Series</text>\n", | |
| "</g>\n", | |
| "<!-- due_date->possible_dates -->\n", | |
| "<g id=\"edge2\" class=\"edge\">\n", | |
| "<title>due_date->possible_dates</title>\n", | |
| "<path fill=\"none\" stroke=\"black\" d=\"M314.68,-40.7C336.24,-45.52 363.51,-51.62 388.48,-57.2\"/>\n", | |
| "<polygon fill=\"black\" stroke=\"black\" points=\"387.39,-60.54 397.91,-59.31 388.92,-53.71 387.39,-60.54\"/>\n", | |
| "</g>\n", | |
| "<!-- _due_date_inputs -->\n", | |
| "<g id=\"node3\" class=\"node\">\n", | |
| "<title>_due_date_inputs</title>\n", | |
| "<polygon fill=\"#ffffff\" stroke=\"black\" stroke-dasharray=\"5,2\" points=\"148.1,-54.1 0,-54.1 0,-9.5 148.1,-9.5 148.1,-54.1\"/>\n", | |
| "<text text-anchor=\"start\" x=\"14.8\" y=\"-26\" font-family=\"Helvetica,sans-Serif\" font-size=\"14.00\">start_date</text>\n", | |
| "<text text-anchor=\"start\" x=\"80.8\" y=\"-26\" font-family=\"Helvetica,sans-Serif\" font-size=\"14.00\">datetime</text>\n", | |
| "</g>\n", | |
| "<!-- _due_date_inputs->due_date -->\n", | |
| "<g id=\"edge1\" class=\"edge\">\n", | |
| "<title>_due_date_inputs->due_date</title>\n", | |
| "<path fill=\"none\" stroke=\"black\" d=\"M148.44,-31.8C172.88,-31.8 199.56,-31.8 221.92,-31.8\"/>\n", | |
| "<polygon fill=\"black\" stroke=\"black\" points=\"221.67,-35.3 231.67,-31.8 221.67,-28.3 221.67,-35.3\"/>\n", | |
| "</g>\n", | |
| "<!-- _possible_dates_inputs -->\n", | |
| "<g id=\"node4\" class=\"node\">\n", | |
| "<title>_possible_dates_inputs</title>\n", | |
| "<polygon fill=\"#ffffff\" stroke=\"black\" stroke-dasharray=\"5,2\" points=\"370.7,-147.6 177.1,-147.6 177.1,-82 370.7,-82 370.7,-147.6\"/>\n", | |
| "<text text-anchor=\"start\" x=\"197.52\" y=\"-119.5\" font-family=\"Helvetica,sans-Serif\" font-size=\"14.00\">buffer_after_due_date</text>\n", | |
| "<text text-anchor=\"start\" x=\"341.77\" y=\"-119.5\" font-family=\"Helvetica,sans-Serif\" font-size=\"14.00\">int</text>\n", | |
| "<text text-anchor=\"start\" x=\"191.9\" y=\"-98.5\" font-family=\"Helvetica,sans-Serif\" font-size=\"14.00\">buffer_before_due_date</text>\n", | |
| "<text text-anchor=\"start\" x=\"341.77\" y=\"-98.5\" font-family=\"Helvetica,sans-Serif\" font-size=\"14.00\">int</text>\n", | |
| "</g>\n", | |
| "<!-- _possible_dates_inputs->possible_dates -->\n", | |
| "<g id=\"edge3\" class=\"edge\">\n", | |
| "<title>_possible_dates_inputs->possible_dates</title>\n", | |
| "<path fill=\"none\" stroke=\"black\" d=\"M371.14,-92.75C377.04,-91.4 382.92,-90.06 388.67,-88.74\"/>\n", | |
| "<polygon fill=\"black\" stroke=\"black\" points=\"389.11,-92.23 398.08,-86.58 387.55,-85.41 389.11,-92.23\"/>\n", | |
| "</g>\n", | |
| "<!-- input -->\n", | |
| "<g id=\"node5\" class=\"node\">\n", | |
| "<title>input</title>\n", | |
| "<polygon fill=\"#ffffff\" stroke=\"black\" stroke-dasharray=\"5,2\" points=\"101.05,-109.1 47.05,-109.1 47.05,-72.5 101.05,-72.5 101.05,-109.1\"/>\n", | |
| "<text text-anchor=\"middle\" x=\"74.05\" y=\"-85\" font-family=\"Helvetica,sans-Serif\" font-size=\"14.00\">input</text>\n", | |
| "</g>\n", | |
| "<!-- function -->\n", | |
| "<g id=\"node6\" class=\"node\">\n", | |
| "<title>function</title>\n", | |
| "<path fill=\"#b4d8e4\" stroke=\"black\" d=\"M96.47,-164.1C96.47,-164.1 51.62,-164.1 51.62,-164.1 45.62,-164.1 39.62,-158.1 39.62,-152.1 39.62,-152.1 39.62,-139.5 39.62,-139.5 39.62,-133.5 45.62,-127.5 51.62,-127.5 51.62,-127.5 96.47,-127.5 96.47,-127.5 102.47,-127.5 108.47,-133.5 108.47,-139.5 108.47,-139.5 108.47,-152.1 108.47,-152.1 108.47,-158.1 102.47,-164.1 96.47,-164.1\"/>\n", | |
| "<text text-anchor=\"middle\" x=\"74.05\" y=\"-140\" font-family=\"Helvetica,sans-Serif\" font-size=\"14.00\">function</text>\n", | |
| "</g>\n", | |
| "</g>\n", | |
| "</svg>\n" | |
| ], | |
| "text/plain": [ | |
| "<graphviz.graphs.Digraph at 0x2b6d5e890>" | |
| ] | |
| }, | |
| "metadata": {}, | |
| "output_type": "display_data" | |
| } | |
| ], | |
| "source": [ | |
| "%%cell_to_module base_dates --display -w\n", | |
| "import pandas as pd\n", | |
| "import datetime\n", | |
| "\n", | |
| "def due_date(start_date: datetime.datetime) -> datetime.datetime:\n", | |
| " \"\"\"The due date is start_date + 40 weeks. Start date is the date of the expecting mother's last period\"\"\"\n", | |
| " return start_date + datetime.timedelta(weeks=40)\n", | |
| " \n", | |
| "def possible_dates(due_date: datetime.datetime, buffer_before_due_date:int=8*7, buffer_after_due_date:int=4*7) -> pd.Series:\n", | |
| " \"\"\"Gets all the reasonably possible dates (-8 weeks, + 4 weeks) of delivery\"\"\"\n", | |
| " idx = pd.date_range(\n", | |
| " due_date-datetime.timedelta(days=buffer_before_due_date),\n", | |
| " due_date+datetime.timedelta(days=buffer_after_due_date)\n", | |
| " )\n", | |
| " return pd.Series(data=idx, index=idx)" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "id": "59d80d95", | |
| "metadata": {}, | |
| "source": [ | |
| "<a id=\"distributions\"></a>\n", | |
| "\n", | |
| "# Computing Probability Distributions\n", | |
| "\n", | |
| "This cell defines functions to compute the probabilities. Note that we have hardcoded the probability distribution -- see the end of the notebook for how we figured this out.\n", | |
| "\n", | |
| "We have:\n", | |
| "1. The probability_distribution -- a continuous distribution\n", | |
| "2. The full pdf (probability distribution function). This does two clever things\n", | |
| " a. Readjusts the probability given the current date (see code). You can pass a current_date of `None` if you want to bypass\n", | |
| " b. Again readjusts the probability given the date after which they will induce. You can pass an `induction_post_due_date_days` of something large if you don't want to think about it." | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 29, | |
| "id": "4f558bab", | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "data": { | |
| "image/svg+xml": [ | |
| "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n", | |
| "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n", | |
| " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n", | |
| "<!-- Generated by graphviz version 12.0.0 (20240704.0754)\n", | |
| " -->\n", | |
| "<!-- Pages: 1 -->\n", | |
| "<svg width=\"871pt\" height=\"346pt\"\n", | |
| " viewBox=\"0.00 0.00 870.90 345.80\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n", | |
| "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 341.8)\">\n", | |
| "<polygon fill=\"white\" stroke=\"none\" points=\"-4,4 -4,-341.8 866.9,-341.8 866.9,4 -4,4\"/>\n", | |
| "<g id=\"clust1\" class=\"cluster\">\n", | |
| "<title>cluster__legend</title>\n", | |
| "<polygon fill=\"#ffffff\" stroke=\"black\" points=\"94.38,-199.8 94.38,-329.8 179.23,-329.8 179.23,-199.8 94.38,-199.8\"/>\n", | |
| "<text text-anchor=\"middle\" x=\"136.8\" y=\"-312.5\" font-family=\"Helvetica,sans-Serif\" font-size=\"14.00\">Legend</text>\n", | |
| "</g>\n", | |
| "<!-- full_pdf -->\n", | |
| "<g id=\"node1\" class=\"node\">\n", | |
| "<title>full_pdf</title>\n", | |
| "<path fill=\"#b4d8e4\" stroke=\"black\" d=\"M407.7,-137.6C407.7,-137.6 361.35,-137.6 361.35,-137.6 355.35,-137.6 349.35,-131.6 349.35,-125.6 349.35,-125.6 349.35,-86 349.35,-86 349.35,-80 355.35,-74 361.35,-74 361.35,-74 407.7,-74 407.7,-74 413.7,-74 419.7,-80 419.7,-86 419.7,-86 419.7,-125.6 419.7,-125.6 419.7,-131.6 413.7,-137.6 407.7,-137.6\"/>\n", | |
| "<text text-anchor=\"start\" x=\"360.15\" y=\"-114.5\" font-family=\"Helvetica,sans-Serif\" font-weight=\"bold\" font-size=\"14.00\">full_pdf</text>\n", | |
| "<text text-anchor=\"start\" x=\"365.4\" y=\"-86.5\" font-family=\"Helvetica,sans-Serif\" font-style=\"italic\" font-size=\"14.00\">Series</text>\n", | |
| "</g>\n", | |
| "<!-- probability_on_date -->\n", | |
| "<g id=\"node3\" class=\"node\">\n", | |
| "<title>probability_on_date</title>\n", | |
| "<path fill=\"#b4d8e4\" stroke=\"black\" d=\"M640.3,-245.6C640.3,-245.6 514.45,-245.6 514.45,-245.6 508.45,-245.6 502.45,-239.6 502.45,-233.6 502.45,-233.6 502.45,-194 502.45,-194 502.45,-188 508.45,-182 514.45,-182 514.45,-182 640.3,-182 640.3,-182 646.3,-182 652.3,-188 652.3,-194 652.3,-194 652.3,-233.6 652.3,-233.6 652.3,-239.6 646.3,-245.6 640.3,-245.6\"/>\n", | |
| "<text text-anchor=\"start\" x=\"513.25\" y=\"-222.5\" font-family=\"Helvetica,sans-Serif\" font-weight=\"bold\" font-size=\"14.00\">probability_on_date</text>\n", | |
| "<text text-anchor=\"start\" x=\"558.25\" y=\"-194.5\" font-family=\"Helvetica,sans-Serif\" font-style=\"italic\" font-size=\"14.00\">Series</text>\n", | |
| "</g>\n", | |
| "<!-- full_pdf->probability_on_date -->\n", | |
| "<g id=\"edge5\" class=\"edge\">\n", | |
| "<title>full_pdf->probability_on_date</title>\n", | |
| "<path fill=\"none\" stroke=\"black\" d=\"M419.77,-127.63C441.26,-141.08 469.68,-158.45 495.45,-172.8 497.49,-173.94 499.57,-175.08 501.67,-176.23\"/>\n", | |
| "<polygon fill=\"black\" stroke=\"black\" points=\"499.84,-179.22 510.31,-180.86 503.15,-173.05 499.84,-179.22\"/>\n", | |
| "</g>\n", | |
| "<!-- full_cdf -->\n", | |
| "<g id=\"node5\" class=\"node\">\n", | |
| "<title>full_cdf</title>\n", | |
| "<path fill=\"#b4d8e4\" stroke=\"black\" d=\"M600.18,-101.6C600.18,-101.6 554.58,-101.6 554.58,-101.6 548.58,-101.6 542.58,-95.6 542.58,-89.6 542.58,-89.6 542.58,-50 542.58,-50 542.58,-44 548.58,-38 554.58,-38 554.58,-38 600.18,-38 600.18,-38 606.18,-38 612.18,-44 612.18,-50 612.18,-50 612.18,-89.6 612.18,-89.6 612.18,-95.6 606.18,-101.6 600.18,-101.6\"/>\n", | |
| "<text text-anchor=\"start\" x=\"553.38\" y=\"-78.5\" font-family=\"Helvetica,sans-Serif\" font-weight=\"bold\" font-size=\"14.00\">full_cdf</text>\n", | |
| "<text text-anchor=\"start\" x=\"558.25\" y=\"-50.5\" font-family=\"Helvetica,sans-Serif\" font-style=\"italic\" font-size=\"14.00\">Series</text>\n", | |
| "</g>\n", | |
| "<!-- full_pdf->full_cdf -->\n", | |
| "<g id=\"edge7\" class=\"edge\">\n", | |
| "<title>full_pdf->full_cdf</title>\n", | |
| "<path fill=\"none\" stroke=\"black\" d=\"M420.09,-99.28C451.26,-93.4 497.3,-84.72 531.35,-78.29\"/>\n", | |
| "<polygon fill=\"black\" stroke=\"black\" points=\"531.73,-81.78 540.9,-76.49 530.43,-74.91 531.73,-81.78\"/>\n", | |
| "</g>\n", | |
| "<!-- probability_before_date -->\n", | |
| "<g id=\"node2\" class=\"node\">\n", | |
| "<title>probability_before_date</title>\n", | |
| "<path fill=\"#b4d8e4\" stroke=\"black\" d=\"M850.9,-137.6C850.9,-137.6 700.3,-137.6 700.3,-137.6 694.3,-137.6 688.3,-131.6 688.3,-125.6 688.3,-125.6 688.3,-86 688.3,-86 688.3,-80 694.3,-74 700.3,-74 700.3,-74 850.9,-74 850.9,-74 856.9,-74 862.9,-80 862.9,-86 862.9,-86 862.9,-125.6 862.9,-125.6 862.9,-131.6 856.9,-137.6 850.9,-137.6\"/>\n", | |
| "<text text-anchor=\"start\" x=\"699.1\" y=\"-114.5\" font-family=\"Helvetica,sans-Serif\" font-weight=\"bold\" font-size=\"14.00\">probability_before_date</text>\n", | |
| "<text text-anchor=\"start\" x=\"756.48\" y=\"-86.5\" font-family=\"Helvetica,sans-Serif\" font-style=\"italic\" font-size=\"14.00\">Series</text>\n", | |
| "</g>\n", | |
| "<!-- probability_distribution -->\n", | |
| "<g id=\"node4\" class=\"node\">\n", | |
| "<title>probability_distribution</title>\n", | |
| "<path fill=\"#b4d8e4\" stroke=\"black\" d=\"M210.98,-189.6C210.98,-189.6 62.63,-189.6 62.63,-189.6 56.63,-189.6 50.63,-183.6 50.63,-177.6 50.63,-177.6 50.63,-138 50.63,-138 50.63,-132 56.63,-126 62.63,-126 62.63,-126 210.98,-126 210.98,-126 216.98,-126 222.98,-132 222.98,-138 222.98,-138 222.98,-177.6 222.98,-177.6 222.98,-183.6 216.98,-189.6 210.98,-189.6\"/>\n", | |
| "<text text-anchor=\"start\" x=\"61.43\" y=\"-166.5\" font-family=\"Helvetica,sans-Serif\" font-weight=\"bold\" font-size=\"14.00\">probability_distribution</text>\n", | |
| "<text text-anchor=\"start\" x=\"94.8\" y=\"-138.5\" font-family=\"Helvetica,sans-Serif\" font-style=\"italic\" font-size=\"14.00\">rv_continuous</text>\n", | |
| "</g>\n", | |
| "<!-- probability_distribution->full_pdf -->\n", | |
| "<g id=\"edge1\" class=\"edge\">\n", | |
| "<title>probability_distribution->full_pdf</title>\n", | |
| "<path fill=\"none\" stroke=\"black\" d=\"M223.4,-139.69C261.89,-131.54 305.76,-122.26 337.84,-115.47\"/>\n", | |
| "<polygon fill=\"black\" stroke=\"black\" points=\"338.56,-118.89 347.61,-113.4 337.11,-112.05 338.56,-118.89\"/>\n", | |
| "</g>\n", | |
| "<!-- full_cdf->probability_before_date -->\n", | |
| "<g id=\"edge3\" class=\"edge\">\n", | |
| "<title>full_cdf->probability_before_date</title>\n", | |
| "<path fill=\"none\" stroke=\"black\" d=\"M612.55,-76.07C630.58,-79.38 653.7,-83.62 676.8,-87.86\"/>\n", | |
| "<polygon fill=\"black\" stroke=\"black\" points=\"676.16,-91.3 686.62,-89.66 677.42,-84.41 676.16,-91.3\"/>\n", | |
| "</g>\n", | |
| "<!-- _full_pdf_inputs -->\n", | |
| "<g id=\"node6\" class=\"node\">\n", | |
| "<title>_full_pdf_inputs</title>\n", | |
| "<polygon fill=\"#ffffff\" stroke=\"black\" stroke-dasharray=\"5,2\" points=\"273.6,-107.6 0,-107.6 0,0 273.6,0 273.6,-107.6\"/>\n", | |
| "<text text-anchor=\"start\" x=\"69.93\" y=\"-79.5\" font-family=\"Helvetica,sans-Serif\" font-size=\"14.00\">current_date</text>\n", | |
| "<text text-anchor=\"start\" x=\"207.3\" y=\"-79.5\" font-family=\"Helvetica,sans-Serif\" font-size=\"14.00\">Optional</text>\n", | |
| "<text text-anchor=\"start\" x=\"14.43\" y=\"-58.5\" font-family=\"Helvetica,sans-Serif\" font-size=\"14.00\">induction_post_due_date_days</text>\n", | |
| "<text text-anchor=\"start\" x=\"225.68\" y=\"-58.5\" font-family=\"Helvetica,sans-Serif\" font-size=\"14.00\">int</text>\n", | |
| "<text text-anchor=\"start\" x=\"79.68\" y=\"-37.5\" font-family=\"Helvetica,sans-Serif\" font-size=\"14.00\">due_date</text>\n", | |
| "<text text-anchor=\"start\" x=\"206.55\" y=\"-37.5\" font-family=\"Helvetica,sans-Serif\" font-size=\"14.00\">datetime</text>\n", | |
| "<text text-anchor=\"start\" x=\"77.8\" y=\"-16.5\" font-family=\"Helvetica,sans-Serif\" font-size=\"14.00\">start_date</text>\n", | |
| "<text text-anchor=\"start\" x=\"206.55\" y=\"-16.5\" font-family=\"Helvetica,sans-Serif\" font-size=\"14.00\">datetime</text>\n", | |
| "</g>\n", | |
| "<!-- _full_pdf_inputs->full_pdf -->\n", | |
| "<g id=\"edge2\" class=\"edge\">\n", | |
| "<title>_full_pdf_inputs->full_pdf</title>\n", | |
| "<path fill=\"none\" stroke=\"black\" d=\"M273.96,-82.61C296.96,-87.48 319.33,-92.21 337.79,-96.12\"/>\n", | |
| "<polygon fill=\"black\" stroke=\"black\" points=\"337.06,-99.54 347.56,-98.19 338.51,-92.7 337.06,-99.54\"/>\n", | |
| "</g>\n", | |
| "<!-- _probability_before_date_inputs -->\n", | |
| "<g id=\"node7\" class=\"node\">\n", | |
| "<title>_probability_before_date_inputs</title>\n", | |
| "<polygon fill=\"#ffffff\" stroke=\"black\" stroke-dasharray=\"5,2\" points=\"659.3,-164.1 495.45,-164.1 495.45,-119.5 659.3,-119.5 659.3,-164.1\"/>\n", | |
| "<text text-anchor=\"start\" x=\"510.25\" y=\"-136\" font-family=\"Helvetica,sans-Serif\" font-size=\"14.00\">possible_dates</text>\n", | |
| "<text text-anchor=\"start\" x=\"606.25\" y=\"-136\" font-family=\"Helvetica,sans-Serif\" font-size=\"14.00\">Series</text>\n", | |
| "</g>\n", | |
| "<!-- _probability_before_date_inputs->probability_before_date -->\n", | |
| "<g id=\"edge4\" class=\"edge\">\n", | |
| "<title>_probability_before_date_inputs->probability_before_date</title>\n", | |
| "<path fill=\"none\" stroke=\"black\" d=\"M659.6,-126.9C665.32,-125.85 671.12,-124.78 676.91,-123.72\"/>\n", | |
| "<polygon fill=\"black\" stroke=\"black\" points=\"677.34,-127.2 686.55,-121.95 676.08,-120.32 677.34,-127.2\"/>\n", | |
| "</g>\n", | |
| "<!-- _probability_on_date_inputs -->\n", | |
| "<g id=\"node8\" class=\"node\">\n", | |
| "<title>_probability_on_date_inputs</title>\n", | |
| "<polygon fill=\"#ffffff\" stroke=\"black\" stroke-dasharray=\"5,2\" points=\"466.45,-236.1 302.6,-236.1 302.6,-191.5 466.45,-191.5 466.45,-236.1\"/>\n", | |
| "<text text-anchor=\"start\" x=\"317.4\" y=\"-208\" font-family=\"Helvetica,sans-Serif\" font-size=\"14.00\">possible_dates</text>\n", | |
| "<text text-anchor=\"start\" x=\"413.4\" y=\"-208\" font-family=\"Helvetica,sans-Serif\" font-size=\"14.00\">Series</text>\n", | |
| "</g>\n", | |
| "<!-- _probability_on_date_inputs->probability_on_date -->\n", | |
| "<g id=\"edge6\" class=\"edge\">\n", | |
| "<title>_probability_on_date_inputs->probability_on_date</title>\n", | |
| "<path fill=\"none\" stroke=\"black\" d=\"M466.74,-213.8C474.74,-213.8 482.87,-213.8 490.91,-213.8\"/>\n", | |
| "<polygon fill=\"black\" stroke=\"black\" points=\"490.68,-217.3 500.68,-213.8 490.68,-210.3 490.68,-217.3\"/>\n", | |
| "</g>\n", | |
| "<!-- input -->\n", | |
| "<g id=\"node9\" class=\"node\">\n", | |
| "<title>input</title>\n", | |
| "<polygon fill=\"#ffffff\" stroke=\"black\" stroke-dasharray=\"5,2\" points=\"163.8,-244.1 109.8,-244.1 109.8,-207.5 163.8,-207.5 163.8,-244.1\"/>\n", | |
| "<text text-anchor=\"middle\" x=\"136.8\" y=\"-220\" font-family=\"Helvetica,sans-Serif\" font-size=\"14.00\">input</text>\n", | |
| "</g>\n", | |
| "<!-- function -->\n", | |
| "<g id=\"node10\" class=\"node\">\n", | |
| "<title>function</title>\n", | |
| "<path fill=\"#b4d8e4\" stroke=\"black\" d=\"M159.23,-299.1C159.23,-299.1 114.38,-299.1 114.38,-299.1 108.38,-299.1 102.38,-293.1 102.38,-287.1 102.38,-287.1 102.38,-274.5 102.38,-274.5 102.38,-268.5 108.38,-262.5 114.38,-262.5 114.38,-262.5 159.23,-262.5 159.23,-262.5 165.23,-262.5 171.23,-268.5 171.23,-274.5 171.23,-274.5 171.23,-287.1 171.23,-287.1 171.23,-293.1 165.23,-299.1 159.23,-299.1\"/>\n", | |
| "<text text-anchor=\"middle\" x=\"136.8\" y=\"-275\" font-family=\"Helvetica,sans-Serif\" font-size=\"14.00\">function</text>\n", | |
| "</g>\n", | |
| "</g>\n", | |
| "</svg>\n" | |
| ], | |
| "text/plain": [ | |
| "<graphviz.graphs.Digraph at 0x2b1722d10>" | |
| ] | |
| }, | |
| "metadata": {}, | |
| "output_type": "display_data" | |
| } | |
| ], | |
| "source": [ | |
| "%%cell_to_module probabilities --display -w\n", | |
| "\n", | |
| "import pandas as pd\n", | |
| "import datetime\n", | |
| "from scipy import stats\n", | |
| "from typing import Optional\n", | |
| "\n", | |
| "\n", | |
| "def probability_distribution() -> stats.rv_continuous:\n", | |
| " \"\"\"These were reverse engineered from https://datayze.com/labor-probability-calculator -- see notes on how it was done (at the end).\"\"\"\n", | |
| " params = {\n", | |
| " 'a': -4.186168447183817,\n", | |
| " 'loc': 294.44465059093034,\n", | |
| " 'scale': 20.670154416450384\n", | |
| " }\n", | |
| " return stats.skewnorm(**params)\n", | |
| " \n", | |
| "def full_pdf(\n", | |
| " start_date: datetime.datetime, \n", | |
| " due_date: datetime.datetime,\n", | |
| " probability_distribution: stats.rv_continuous, \n", | |
| " current_date: Optional[datetime.datetime]=None,\n", | |
| " induction_post_due_date_days:int=14\n", | |
| ") -> pd.Series:\n", | |
| " \"\"\"Probabilities of delivery on X date on the *full* date range. We'll filter later.\n", | |
| " Note this does\n", | |
| " \"\"\"\n", | |
| " all_dates = pd.date_range(start_date, start_date + datetime.timedelta(days=365)) # Wide range but we'll cut it down later\n", | |
| " raw_pdf = probability_distribution.pdf([(item-pd.Timestamp(start_date)).days for item in all_dates])\n", | |
| " pdf = pd.Series(index=all_dates, data=raw_pdf)\n", | |
| " if current_date is not None:\n", | |
| " # rejuggle pdf\n", | |
| " # Use a simple parficle filter approach: https://en.wikipedia.org/wiki/Particle_filter\n", | |
| " pdf[pdf.index < current_date] = 0\n", | |
| " pdf_sum = sum(pdf)\n", | |
| " pdf = pdf/pdf_sum\n", | |
| " induction_date = due_date + datetime.timedelta(days=induction_post_due_date_days)\n", | |
| " probability_past_induction_date = sum(pdf[pdf.index > induction_date])\n", | |
| " pdf[pdf.index > induction_date] = 0\n", | |
| " pdf[induction_date] = probability_past_induction_date\n", | |
| " return pdf\n", | |
| "\n", | |
| "def full_cdf(\n", | |
| " full_pdf: pd.Series\n", | |
| ") -> pd.Series:\n", | |
| " \"\"\"Probability of delivery prior to X date on the *full* date range. We'll filter later.\"\"\"\n", | |
| " return full_pdf.cumsum()\n", | |
| "\n", | |
| "def probability_on_date(full_pdf: pd.Series, possible_dates: pd.Series) -> pd.Series:\n", | |
| " \"\"\"Probability of deliver *on* a date for every date in the specified date range\"\"\"\n", | |
| " return full_pdf[possible_dates]\n", | |
| " \n", | |
| "def probability_before_date(full_cdf: pd.Series, possible_dates: pd.Series) -> pd.Series:\n", | |
| " \"\"\"Probability of delivery *before* a date for every date in the specified date range\"\"\"\n", | |
| " return full_cdf[possible_dates]" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "id": "91687966", | |
| "metadata": {}, | |
| "source": [ | |
| "<a id=\"analysis\"></a>\n", | |
| "\n", | |
| "# Analysis\n", | |
| "\n", | |
| "We run the code and look at the distribution here -- the clanedar display highlights by likelihood (on that day).\n", | |
| "The plots show CDF/PDF." | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 30, | |
| "id": "9f7d1777", | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "data": { | |
| "text/html": [ | |
| "<table><tr><td><table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" class=\"month\">\n", | |
| "<tr><th colspan=\"7\" class=\"month\">May 2024</th></tr>\n", | |
| "<tr><th class=\"mon\">Mon</th><th class=\"tue\">Tue</th><th class=\"wed\">Wed</th><th class=\"thu\">Thu</th><th class=\"fri\">Fri</th><th class=\"sat\">Sat</th><th class=\"sun\">Sun</th></tr>\n", | |
| "<tr><td class=\"noday\"> </td><td class=\"noday\"> </td><td class=\"wed\">1</td><td class=\"thu\">2</td><td class=\"fri\">3</td><td class=\"sat\">4</td><td class=\"sun\">5</td></tr>\n", | |
| "<tr><td class=\"mon\">6</td><td class=\"tue\">7</td><td class=\"wed\">8</td><td class=\"thu\">9</td><td class=\"fri\">10</td><td class=\"sat\">11</td><td class=\"sun\">12</td></tr>\n", | |
| "<tr><td class=\"mon\">13</td><td class=\"tue\">14</td><td class=\"wed\">15</td><td class=\"thu\">16</td><td class=\"fri\">17</td><td class=\"sat\">18</td><td class=\"sun\">19</td></tr>\n", | |
| "<tr><td class=\"mon\">20</td><td class=\"tue\">21</td><td class=\"wed\">22</td><td class=\"thu\" style=\"background-color:rgba(227, 30, 48, 0.0);\">23</td><td class=\"fri\" style=\"background-color:rgba(227, 30, 48, 0.0);\">24</td><td class=\"sat\" style=\"background-color:rgba(227, 30, 48, 0.0);\">25</td><td class=\"sun\" style=\"background-color:rgba(227, 30, 48, 0.0);\">26</td></tr>\n", | |
| "<tr><td class=\"mon\" style=\"background-color:rgba(227, 30, 48, 0.0);\">27</td><td class=\"tue\" style=\"background-color:rgba(227, 30, 48, 0.0);\">28</td><td class=\"wed\" style=\"background-color:rgba(227, 30, 48, 0.0);\">29</td><td class=\"thu\" style=\"background-color:rgba(227, 30, 48, 0.0);\">30</td><td class=\"fri\" style=\"background-color:rgba(227, 30, 48, 0.0);\">31</td><td class=\"noday\"> </td><td class=\"noday\"> </td></tr>\n", | |
| "</table>\n", | |
| "</td><td><table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" class=\"month\">\n", | |
| "<tr><th colspan=\"7\" class=\"month\">June 2024</th></tr>\n", | |
| "<tr><th class=\"mon\">Mon</th><th class=\"tue\">Tue</th><th class=\"wed\">Wed</th><th class=\"thu\">Thu</th><th class=\"fri\">Fri</th><th class=\"sat\">Sat</th><th class=\"sun\">Sun</th></tr>\n", | |
| "<tr><td class=\"noday\"> </td><td class=\"noday\"> </td><td class=\"noday\"> </td><td class=\"noday\"> </td><td class=\"noday\"> </td><td class=\"sat\" style=\"background-color:rgba(227, 30, 48, 0.0);\">1</td><td class=\"sun\" style=\"background-color:rgba(227, 30, 48, 0.0);\">2</td></tr>\n", | |
| "<tr><td class=\"mon\" style=\"background-color:rgba(227, 30, 48, 0.0);\">3</td><td class=\"tue\" style=\"background-color:rgba(227, 30, 48, 0.0);\">4</td><td class=\"wed\" style=\"background-color:rgba(227, 30, 48, 0.0);\">5</td><td class=\"thu\" style=\"background-color:rgba(227, 30, 48, 0.0);\">6</td><td class=\"fri\" style=\"background-color:rgba(227, 30, 48, 0.0);\">7</td><td class=\"sat\" style=\"background-color:rgba(227, 30, 48, 0.0);\">8</td><td class=\"sun\" style=\"background-color:rgba(227, 30, 48, 0.0);\">9</td></tr>\n", | |
| "<tr><td class=\"mon\" style=\"background-color:rgba(227, 30, 48, 0.0);\">10</td><td class=\"tue\" style=\"background-color:rgba(227, 30, 48, 0.0);\">11</td><td class=\"wed\" style=\"background-color:rgba(227, 30, 48, 0.0);\">12</td><td class=\"thu\" style=\"background-color:rgba(227, 30, 48, 0.0);\">13</td><td class=\"fri\" style=\"background-color:rgba(227, 30, 48, 0.0);\">14</td><td class=\"sat\" style=\"background-color:rgba(227, 30, 48, 0.0);\">15</td><td class=\"sun\" style=\"background-color:rgba(227, 30, 48, 0.0);\">16</td></tr>\n", | |
| "<tr><td class=\"mon\" style=\"background-color:rgba(227, 30, 48, 0.0);\">17</td><td class=\"tue\" style=\"background-color:rgba(227, 30, 48, 0.0);\">18</td><td class=\"wed\" style=\"background-color:rgba(227, 30, 48, 0.0);\">19</td><td class=\"thu\" style=\"background-color:rgba(227, 30, 48, 0.0);\">20</td><td class=\"fri\" style=\"background-color:rgba(227, 30, 48, 0.0);\">21</td><td class=\"sat\" style=\"background-color:rgba(227, 30, 48, 0.0);\">22</td><td class=\"sun\" style=\"background-color:rgba(227, 30, 48, 0.0);\">23</td></tr>\n", | |
| "<tr><td class=\"mon\" style=\"background-color:rgba(227, 30, 48, 0.0);\">24</td><td class=\"tue\" style=\"background-color:rgba(227, 30, 48, 0.0);\">25</td><td class=\"wed\" style=\"background-color:rgba(227, 30, 48, 0.0);\">26</td><td class=\"thu\" style=\"background-color:rgba(227, 30, 48, 0.0);\">27</td><td class=\"fri\" style=\"background-color:rgba(227, 30, 48, 0.0);\">28</td><td class=\"sat\" style=\"background-color:rgba(227, 30, 48, 0.0);\">29</td><td class=\"sun\" style=\"background-color:rgba(227, 30, 48, 0.0);\">30</td></tr>\n", | |
| "</table>\n", | |
| "</td><td><table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" class=\"month\">\n", | |
| "<tr><th colspan=\"7\" class=\"month\">July 2024</th></tr>\n", | |
| "<tr><th class=\"mon\">Mon</th><th class=\"tue\">Tue</th><th class=\"wed\">Wed</th><th class=\"thu\">Thu</th><th class=\"fri\">Fri</th><th class=\"sat\">Sat</th><th class=\"sun\">Sun</th></tr>\n", | |
| "<tr><td class=\"mon\" style=\"background-color:rgba(227, 30, 48, 0.0);\">1</td><td class=\"tue\" style=\"background-color:rgba(227, 30, 48, 0.0);\">2</td><td class=\"wed\" style=\"background-color:rgba(227, 30, 48, 0.0);\">3</td><td class=\"thu\" style=\"background-color:rgba(227, 30, 48, 0.0);\">4</td><td class=\"fri\" style=\"background-color:rgba(227, 30, 48, 0.0);\">5</td><td class=\"sat\" style=\"background-color:rgba(227, 30, 48, 0.0);\">6</td><td class=\"sun\" style=\"background-color:rgba(227, 30, 48, 0.0);\">7</td></tr>\n", | |
| "<tr><td class=\"mon\" style=\"background-color:rgba(227, 30, 48, 0.0);\">8</td><td class=\"tue\" style=\"background-color:rgba(227, 30, 48, 0.0);\">9</td><td class=\"wed\" style=\"background-color:rgba(227, 30, 48, 0.0);\">10</td><td class=\"thu\" style=\"background-color:rgba(227, 30, 48, 0.0);\">11</td><td class=\"fri\" style=\"background-color:rgba(227, 30, 48, 0.0);\">12</td><td class=\"sat\" style=\"background-color:rgba(227, 30, 48, 0.10129075856628583);\">13</td><td class=\"sun\" style=\"background-color:rgba(227, 30, 48, 0.10587751708387277);\">14</td></tr>\n", | |
| "<tr><td class=\"mon\" style=\"background-color:rgba(227, 30, 48, 0.11040671345380691);\">15</td><td class=\"tue\" style=\"background-color:rgba(227, 30, 48, 0.11484714596838565);\">16</td><td class=\"wed\" style=\"background-color:rgba(227, 30, 48, 0.1191607984807029);\">17</td><td class=\"thu\" style=\"background-color:rgba(227, 30, 48, 0.12329884963770736);\">18</td><td class=\"fri\" style=\"background-color:rgba(227, 30, 48, 0.12719599693544803);\">19</td><td class=\"sat\" style=\"background-color:rgba(227, 30, 48, 0.13076321138591065);\">20</td><td class=\"sun\" style=\"background-color:rgba(227, 30, 48, 0.13387970326354187);\">21</td></tr>\n", | |
| "<tr><td class=\"mon\" style=\"background-color:rgba(227, 30, 48, 0.13638581613408116);\">22</td><td class=\"tue\" style=\"background-color:rgba(227, 30, 48, 0.1380795827028641);\">23</td><td class=\"wed\" style=\"background-color:rgba(227, 30, 48, 0.13872038732436798);\">24</td><td class=\"thu\" style=\"background-color:rgba(227, 30, 48, 0.13804307181346667);\">25</td><td class=\"fri\" style=\"background-color:rgba(227, 30, 48, 0.13578443133954285);\">26</td><td class=\"sat\" style=\"background-color:rgba(227, 30, 48, 0.1317212355151385);\">27</td><td class=\"sun\" style=\"background-color:rgba(227, 30, 48, 0.1257151046172509);\">28</td></tr>\n", | |
| "<tr><td class=\"mon\" style=\"background-color:rgba(227, 30, 48, 0.1177558332507217);\">29</td><td class=\"tue\" style=\"background-color:rgba(227, 30, 48, 0.10799253500942844);\">30</td><td class=\"wed\" style=\"background-color:rgba(227, 30, 48, 0.09674258350235827);\">31</td><td class=\"noday\"> </td><td class=\"noday\"> </td><td class=\"noday\"> </td><td class=\"noday\"> </td></tr>\n", | |
| "</table>\n", | |
| "</td><td><table border=\"0\" cellpadding=\"0\" cellspacing=\"0\" class=\"month\">\n", | |
| "<tr><th colspan=\"7\" class=\"month\">August 2024</th></tr>\n", | |
| "<tr><th class=\"mon\">Mon</th><th class=\"tue\">Tue</th><th class=\"wed\">Wed</th><th class=\"thu\">Thu</th><th class=\"fri\">Fri</th><th class=\"sat\">Sat</th><th class=\"sun\">Sun</th></tr>\n", | |
| "<tr><td class=\"noday\"> </td><td class=\"noday\"> </td><td class=\"noday\"> </td><td class=\"thu\" style=\"background-color:rgba(227, 30, 48, 0.3);\">1</td><td class=\"fri\" style=\"background-color:rgba(227, 30, 48, 0.0);\">2</td><td class=\"sat\" style=\"background-color:rgba(227, 30, 48, 0.0);\">3</td><td class=\"sun\" style=\"background-color:rgba(227, 30, 48, 0.0);\">4</td></tr>\n", | |
| "<tr><td class=\"mon\" style=\"background-color:rgba(227, 30, 48, 0.0);\">5</td><td class=\"tue\" style=\"background-color:rgba(227, 30, 48, 0.0);\">6</td><td class=\"wed\" style=\"background-color:rgba(227, 30, 48, 0.0);\">7</td><td class=\"thu\" style=\"background-color:rgba(227, 30, 48, 0.0);\">8</td><td class=\"fri\" style=\"background-color:rgba(227, 30, 48, 0.0);\">9</td><td class=\"sat\" style=\"background-color:rgba(227, 30, 48, 0.0);\">10</td><td class=\"sun\" style=\"background-color:rgba(227, 30, 48, 0.0);\">11</td></tr>\n", | |
| "<tr><td class=\"mon\" style=\"background-color:rgba(227, 30, 48, 0.0);\">12</td><td class=\"tue\" style=\"background-color:rgba(227, 30, 48, 0.0);\">13</td><td class=\"wed\" style=\"background-color:rgba(227, 30, 48, 0.0);\">14</td><td class=\"thu\" style=\"background-color:rgba(227, 30, 48, 0.0);\">15</td><td class=\"fri\">16</td><td class=\"sat\">17</td><td class=\"sun\">18</td></tr>\n", | |
| "<tr><td class=\"mon\">19</td><td class=\"tue\">20</td><td class=\"wed\">21</td><td class=\"thu\">22</td><td class=\"fri\">23</td><td class=\"sat\">24</td><td class=\"sun\">25</td></tr>\n", | |
| "<tr><td class=\"mon\">26</td><td class=\"tue\">27</td><td class=\"wed\">28</td><td class=\"thu\">29</td><td class=\"fri\">30</td><td class=\"sat\">31</td><td class=\"noday\"> </td></tr>\n", | |
| "</table>\n", | |
| "</td></tr></table>" | |
| ] | |
| }, | |
| "metadata": {}, | |
| "output_type": "display_data" | |
| } | |
| ], | |
| "source": [ | |
| "from hamilton import base, driver\n", | |
| "\n", | |
| "dr = (\n", | |
| " driver.Builder()\n", | |
| " .with_modules(base_dates, probabilities)\n", | |
| " .with_adapters(base.PandasDataFrameResult())\n", | |
| " .build()\n", | |
| ")\n", | |
| "delivery_probabilities = dr.execute(\n", | |
| " [\"possible_dates\", \"probability_before_date\", \"probability_on_date\"],\n", | |
| " inputs={\"start_date\": PREGNANCY_START_DATE, \"current_date\": TODAY},\n", | |
| ")\n", | |
| "view_date_range(\n", | |
| " delivery_probabilities[\"possible_dates\"], delivery_probabilities[\"probability_on_date\"]\n", | |
| ")" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 31, | |
| "id": "a1181a57", | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "data": { | |
| "image/png": "iVBORw0KGgoAAAANSUhEUgAAA9QAAAMPCAYAAAA0LZ1oAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8g+/7EAAAACXBIWXMAAA9hAAAPYQGoP6dpAADG0UlEQVR4nOzde3yO9ePH8fe982ZmDFtOOWXOhzFMzhRJSPp9JYVCB6WcQuQYJckxoaSj+HZCUVJ9SwfGUJQzEbINM9vscO9w/f5Y981tM9u92b3dez0fD4+26/rc1/257n12t/f9OZkMwzAEAAAAAADyxMXRFQAAAAAAoDgiUAMAAAAAYAcCNQAAAAAAdiBQAwAAAABgBwI1AAAAAAB2IFADAAAAAGAHAjUAAAAAAHYgUAMAAAAAYAcCNQAAuGkMw3B0FRyipN43AJQ0BGoAQIF76KGHFBwcbP1Xt25dNWvWTH379tV7772ntLQ0u6750EMPWb8PDg7W4sWLC7LaBapz5842r0FwcLAaNWqkO+64Q/PmzVNKSkqBPE9BvQ6LFy9WcHBwjmXCw8MVHBys8PBwSdKECRPUuXNn6/nOnTtrwoQJ1u+XLl2qlStX5rtuN4vlfq7+17BhQ7Vr105jxozR0aNH7bpuQd/33r171a1bN5nNZv3000+qW7eupkyZkm3ZkSNHqlWrVoqMjJTZbFb37t3122+/FVhdAAC23BxdAQCAc6pfv76mTp0qSUpPT9elS5e0detWvfTSS4qIiNCCBQvk4mL/57pr165VUFBQQVX3pujQoYOefPJJ6/cpKSkKDw/X0qVLdebMGb322msOrF3eNWjQQGvXrlXt2rWzPb9kyRL5+vpav1+4cKGeeuqpwqqe3aZMmaIGDRpIkpKTk3Xq1Cm99dZb6tevn9555x01bdo0T9cryPtOSUnR+PHjNW7cOHl4eKhdu3YaOHCg3n//fXXq1EmdOnWyln3vvfe0efNmvfHGG9bfjbFjx2r8+PFav369vLy8CqROAIArCNQAgJvC19c3SxDp3LmzatasqVmzZunLL79Ur1697L5+XkOOI5QrVy5LPS29h5999pkmTJigihUrOqZydsjuZ3q1+vXrF15lClDt2rVt7qt169bq1q2b+vbtqwkTJmjjxo1ydXV1SN1Wr14tNzc3de3a1Xps3Lhx2rZtmyZNmqQvvvhCAQEB2rt3r1555RUNGjTIZtRA165dtWDBAn300UcaMmSII24BAJwaQ74BAIVq4MCBCgwM1Jo1a2yOf/zxx7r77rvVsGFDdezYUYsXL1Z6evp1r2MZ6pySkqLmzZtrzpw5NufT0tLUunVrvfjii7l+jgkTJmjQoEGaOnWqQkJC1KNHD40cOVLt27dXRkaGzfUnTZqkbt262fUaNGzYUIZh6OzZs5IyP2iYPXu2Bg0apMaNG2vSpEmSpOjoaE2cOFEdOnRQ48aN1a9fP3333XdZrpeQkKCxY8eqWbNmCgsL04svvqikpCTr+fT0dK1YsUI9e/ZU48aN1bRpU/Xv31/bt2/Pcq1vv/1W3bp1U6NGjXT//fdr27Zt1nPXDvm+1tVDvi3Dx5csWaLg4GAdOXJEwcHBWrt2rc1jzp49q3r16mnDhg3Xfb327dunRx99VK1atVJISIgef/xxHTlyJEu9tm3bpkceeURNmjTR7bffrrlz5+bYhnLi5+enoUOH6q+//tKOHTusx3fu3KlHH31UoaGhatiwoTp37qzFixdb28e1921x+PBhPfbYYwoJCVFISIhGjBihU6dO5VgHs9msVatWqWfPnjbHPT099eqrryouLk6TJ09WQkKCRo0apTp16mjs2LFZrnPPPfdo1apVMpvNdr0WAIDrI1ADAAqVi4uLwsLCtHfvXutc6uXLl+uFF15QWFiYli1bpgcffFBvvvmmXnjhhRtez9PTU926ddNXX31lsxDUL7/8oosXL6p37955eo6IiAidPXtWr7/+usaMGaN+/fopKirKJkQmJyfr66+/1r333mvXa/DXX39JkqpWrWo99uGHH6pRo0ZaunSp+vXrp/Pnz6tfv36KiIjQqFGjtHjxYlWuXFkjRozIEj7ff/99Xb58WQsWLNBjjz2mjz/+2CZYvfrqq1q6dKn+85//6K233tLMmTMVGxurZ555xiZ4S5kfFDz88MNavHixSpUqpWHDhmnfvn15vkdLcO7Xr5/Wrl2r2267TU2aNNH69ettyq1bt04+Pj668847s73O9u3b9cADD0iSZs+erRdffFFnz55V//79dezYMZuyY8eOVfPmzbVs2TL17NlTb731lj7++OM8193i9ttvlyTt2rVLknTw4EENHjxY/v7+mj9/vt544w21aNFCS5Ys0VdffZXtfUuZP+/+/fvrwoULmjNnjmbNmqVTp07pgQce0IULF677/OHh4YqKisr2talXr56eeeYZff/993rooYd08eJFLViwQB4eHlnKdu/eXVFRUTYfDAAACgZDvgEAha58+fJKTU1VbGysPD09rWFv8uTJkqS2bdvK399fkydP1pAhQ3TbbbfleL3evXvr008/1a5du9SiRQtJ0saNG1WzZk01atRI8fHxuX6OtLQ0zZgxwzoHNSMjQ0FBQVq3bp3CwsIkSVu2bFFiYqL69OmTY70Mw7BZgO3ChQvaunWr1qxZox49eqhcuXLWc5UqVbIJwXPnzlVMTIw2b96sypUrS8qckz148GC98sor6tmzp3UOeq1atfT666/LxcVFHTp0kMlk0uzZs3X48GHVqVNH0dHRGjVqlM2ibp6ennr66ad16NAhm+HO06dPV/fu3SVJYWFh6tKli958800tWrQox3u9luWaQUFB1q/vu+8+TZ06VadOnbJ+mLBu3Trdfffd153fO2/ePN16661asWKFddh127Ztdccdd2jRokVauHChtez999+vESNGWOv+7bff6ocfflD//v3zVHeLChUqSJLOnTsnKTNQt2nTRnPnzrW+9rfffru+//57hYeH6+677872vpcsWSJvb2+988471jnmYWFh6tq1q9566y2NHz8+2+ffvn27/Pz8VKNGjWzPP/roo9q8ebP27dun559/XtWqVcu23K233qoyZcpo27Ztatu2rV2vBQAge/RQAwAKnaUn2WQyac+ePUpOTlbnzp2VlpZm/WeZB/rLL7/c8HotW7ZUpUqVtHHjRkmZCzl9++231t7pvDyHv7+/zWJnLi4uuvfee/XNN99Ye3M///xztWnT5oaLoq1bt04NGjSw/mvfvr2mTZumLl26WBdss6hXr57N9zt27FCzZs2sYdqiV69eOnfunI4fP2491r17d5sF3iw9mjt37pSUGUoHDRqkmJgYRURE6NNPP7X2cl89DNjd3d2mN9TT01Pt27e3Xie/LMHZ0ku9e/dunThx4ro9/YmJidq3b5/uuusumznMfn5+6tSpU5Ye12bNmtl8HxQUpMTERLvre3U7laQ+ffrozTffVGpqqg4ePKjNmzdr0aJFSk9PV2pq6nWvs337drVs2VJeXl7Wtufr66sWLVro119/ve7jTp06leXnf7Vjx47pyJEjMplMWrduXY5DuitV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VEHXBQAAAEAxkrs51PRQw3nZFajffPNNde7cWUOHDtWmTZtkNpsLul4AAAAAirhczaFm2yw4MbsC9c8//6yXXnpJhmFo7NixateunaZPn669e/cWdP0AAAAAFFFJKamScrttFouSwflcv+XnwMvLS7169VKvXr0UGRmp9evX6+uvv9aaNWtUu3Zt9e3bV71791a5cuUKur4AAAAAigjrHOpcDPlOpYcaTijfi5IFBQVpyJAhevLJJ9WiRQsdOXJEr7zyijp27Khp06YpISGhIOoJAAAAoAjJyDCUlJIZknPXQ02ghvOxq4faYseOHVq/fr02b96sxMREtW7dWq+99prat2+vrVu3asaMGfrnn3+0YsWKgqovAAAAgCIg2Zxm/drHy/265TzcLXOoGfIN52NXoJ4/f76++OILnT17VrfccosGDx6svn37qlKlStYyPXr00KFDh/Tee+8VWGUBAAAAFA2W4d4uLibrwmPZYR9qODO7AvWqVavUtWtXzZw5U23atJHJZMq2XKNGjfTss8/mp34AAAAAiqDEq1b4vl4ekNg2C87NrkBtWXzMw8Mjy7mUlBT9+eefCgkJUdeuXfNdQQAAAABFj3VBshzmT0uS+79DvplDDWdk16Jk9913nw4ePJjtub1792rIkCH5qhQAAACAos0SqH1yWOFburqHmjnUcD657qGeM2eOYmNjJUmGYWjp0qUqW7ZslnIHDhxQ6dKlC6yCAAAAAIqe3PZQW+dQp9FDDeeT60Bds2ZNvfHGG5Ikk8mkP/74I8uQb1dXV5UuXVoTJ04s2FoCAAAAKFKunkOdEw83ts2C88p1oL7//vt1//33S5I6d+6s119/XfXq1btpFQMAAABQdOW2h5pFyeDM7FqU7Pvvvy/oegAAAAAoRnI7h/rKPtQEajifXAfqhx9+WFOnTlWtWrX08MMP51jWZDLp3XffzXflAAAAABRNeZ5DzaJkcEK5DtSGYWT79Y3KAgAAAHA+icmpknIfqJlDDWeU60D9/vvvZ/s1AAAAgJKHOdSAnftQAwAAACjZrHOob9hDzRxqOK9c91DXrVtXJpMpV2VNJpP279+fq7IZGRlasmSJPv74Y8XHxys0NFRTpkxR1apVsy1/8eJFvfjii9q6datMJpPuvvtuPffcc/L29raW2bt3r+bMmaN9+/apbNmyuu+++/TUU0/J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ZGSkgoKCbB5TsWJFJSUl6eLFi6pQoYI6dOhgc/79999XcnKybr/9duuxSZMmqVOnTrmeJxEVFaWyZcvahCHLc0dGRkrKnB9bsWJFvfTSS+rYsaPuuOMOvfLKK0pJSbnudS2PveWWW657XUmaPXu2HnvsMZvXpSQqae1DkurWrat3331X9erVy/b80aNHlZ6ers2bN6tbt27q2LGjxo0bp+jo6FzVHdkrzm3taosWLVKdOnXUu3fvHK/Le1HelLT2IfFeVNQV5zZ511136f7779e4cePUoEED9erVS7fffrsef/zx6143t+9Zy5cvV//+/XP84LokKGntQ8pcL2Lx4sWqWrVqtucPHz5svY/OnTura9eumjFjhuLj43NV92sRqFFk7d69WxMnTtSdd96pjh07Kjk5OcsfcpbvzWZzlsdv2bJF8+bN0+DBg60Lo6xZs0bHjh3TxIkTc12PpKSkbP+A9PT0tAaihIQEvfnmm0pJSdGSJUs0btw4ffHFF5o8eXKO1736HrK7Lq7P2dtHblj+h+Dt7a2FCxdq1qxZOn78uB5++GElJyfn69q4oji1NYtTp05py5YteuKJJ3J13avvIafrIitnbx+5wXtR0VKc2uSFCxd05swZjRw5Up988olmzZqlH3/8UYsXL87xulffQ3bXxfU5e/vIjcOHD8vFxUUVK1bUsmXLNGHCBP3888968sknlZGRkefrueWrNsBN8u2332rs2LEKCQnRq6++KinzF+zaX2zL997e3jbHP/roI82cOVO9evXSc889J0k6fvy45s6dq5UrV8rHxyfb5x06dKh1CIokTZ8+XV5eXtm+oaSkpFif183NTTVq1NC0adMkSQ0bNlR6erqeffZZTZgwQR9//LGWL19ufew999yj//u//7O5h+yui+yVhPYxY8aMG74Offr0Ufv27W2Ga952221q3769vv/+e/Xo0eOG10DOiltbs9iwYYMCAgKyDM9dtmwZ70UFqCS0D96Lipfi1iYnTZqkW265xfrhTv369WUYhqZNm6aBAwdqwYIF+uKLL6yPfeyxx1SjRg3rPXh5eWV7XWSvJLSPG/VeS9ITTzyhAQMGWIem16lTRxUqVND//d//ad++fTccUn4tAjWKnA8++ECzZs1S9+7dNWfOHOunV7fcckuW4WPR0dHy8fFR6dKlrcfmzp2rt956S0OGDNH48eOtQ302bdqky5cva8iQIdayycnJ2r17tzZv3qw9e/Zo1qxZNp+mBwQEaOvWrYqNjZXZbLb5JC06Oto6nyQoKEi33XabTd0s3585c0b9+/fXXXfdZT3n6+trc51atWple11kVdLax41cO/exYsWK8vf3z3aIJ/KmOLY1i2+//VZ33323dZ6bBe9FBaektY8b4b3I8Ypjm9y1a5c1mFk0bdpUaWlpOn36tJ555hk9+uij1nNlypTR33//bb1OtWrVbK7LVm3XV1LaR264uLhkmedt+bssMjKSQI3ibfXq1Zo5c6YeeughTZo0yWbeS4sWLbRjxw6b8tu3b1dISIj1jwLLL/v48eP1yCOP2JQdOHCg7rnnHptjY8eOVVBQkMaOHStJ2f7x2Lx5c2VkZGjXrl3WRRv++usvRUVFKTQ0VJIUGhqqvXv3yjAMa50PHz4sV1dXValSRf7+/vL3989y7Ro1aig8PNx63bS0NEVERGjAgAG5fs1KkpLWPm5k/vz5+vrrr/X1119br3v69GldvHhRtWvXzvP1cEVxbWtS5hSDAwcO6Nlnn81yDd6LCkZJax83wnuR4xXXNhkYGKhDhw7ZPO7QoUMymUy69dZbVaZMGQUEBNic9/Hxka+vr8LDw62BOi4uTvv379fAgQNz94KVMCWpfeTGc889p+joaL3zzjvWY/v27ZMk+96zCmStcKAAHD9+3GjQoIExYsSILPtYxsXFGYcPHzYaNGhgzJ071zh69KixcuVKm33ytm/fbtSpU8eYOXNmlscnJCRk+5wDBw7M1T55o0ePNjp37mxs377duk/e1UvwHzt2zGjSpInxwgsvGMePHze2bt1qtG/f3pgwYUKO1127dq3RuHFj47PPPrPu/dqqVavrbmFSkreqKYnt42qLFi3KslXNvn37jAYNGhhTpkwxjh8/buzYscPo06eP0b9//xy340LOinNbMwzD2LlzZ5YtTm6E96LcK4nt42q8FxU9xblNrlmzxqhfv77x7rvvGn///bexZcsW4/bbbzemT5+e43Vfe+01o2XLlsa3335rsw+12WzOUvbUqVMletusktg+rjZ+/Pgs74PffvutUadOHWPx4sXGyZMnjR9++MHo3LmzMXr06Fxf92r0UKPI2Lx5s1JTU7VlyxZt2bLF5ty9996rl19+WUuXLtXcuXP17rvvqkqVKpo7d671U60vv/xSUuaKfe+//77N45966ik9/fTTdtdt5syZmj17tp566ilJUvv27W0WlKpZs6bee+89vfLKK+rdu7dKly6tXr16adSoUTle9//+7/8UHx+vBQsWKDY2Vg0bNtSqVatuuIVJSVQS28eNNGzYUG+++aYWLlyovn37ysPDQ126dLEZioW8K85tTZJ16F5eehp5L8q9ktg+boT3Iscqzm3yP//5jzw9PbVq1Sq99tprCgwM1IABAzRs2LAcrzty5EilpaVp8uTJSk5OVmhoqFauXCl3d3e76+qsSmL7uJEuXbpowYIFWrFihd58802VLl1a99xzT7Yjd3LDZBiGka8aAQAAAABQArFtFgAAAAAAdiBQAwAAAABgBwI1AAAAAAB2IFADAAAAAGAHAjUAAAAAAHYgUAMAAAAAYAcCNQAAAAAAdiBQAwCAPDEMw9FVAACgSCBQAwDgxB566CEFBwdb/9WtW1fNmjVT37599d577yktLS1P1zty5IgeeOCBm1RbAACKFzdHVwAAANxc9evX19SpUyVJ6enpunTpkrZu3aqXXnpJERERWrBggVxccvcZ+9dff609e/bczOoCAFBsEKgBAHByvr6+atq0qc2xzp07q2bNmpo1a5a+/PJL9erVyzGVAwCgGGPINwAAJdTAgQMVGBioNWvWSJKSk5M1b9483XnnnWrYsKFCQkI0ZMgQHThwQJK0ePFiLVmyRJIUHBysxYsXS5IyMjK0YsUK3XHHHWrYsKG6deum999/3zE3BQBAIaKHGgCAEsrFxUVhYWHauHGj0tLS9NxzzykiIkKjR49WtWrVdPLkSS1cuFBjxozRxo0bdf/99ysyMlKffPKJ1q5dq6CgIEnStGnT9Nlnn+mxxx5Ts2bNtHPnTs2ePVtxcXEaMWKEg+8SAICbh0ANAEAJVr58eaWmpio2NlaXL1/W5MmT1aNHD0lSy5YtlZCQoJdfflnnz59XUFCQNURbhpD/9ddf+u9//6vRo0dr+PDhkqS2bdvKZDJp+fLlGjBggMqWLeuQewMA4GZjyDcAACWYZQssk8mklStXqkePHoqKitL27du1Zs0a/e9//5Mkmc3mbB+/fft2GYahzp07Ky0tzfqvc+fOSklJ0a5duwrtXgAAKGz0UAMAUIJFRUXJy8tL/v7++umnnzR79mwdP35cpUqVUt26deXj4yPp+ntPx8bGSpLuvvvu614fAABnRaAGAKCESktLU3h4uEJCQnTmzBmNGDFCXbt21fLly1W1alWZTCZ9+OGH+umnn657DT8/P0nSu+++q1KlSmU5X6lSpZtWfwAAHI0h3wAAlFBr167VuXPn9MADD+iPP/5QSkqKhg8frmrVqslkMkmSNUxbeqiv3a+6RYsWkqSLFy+qUaNG1n8xMTFauHChtQcbAABnRA81AABOLiEhQb/99pukzC2uLl68qJ9//llr165Vr169dOedd+rkyZNyc3PT3Llz9cgjj8hsNuuzzz7TDz/8IElKTEyUdKVH+ssvv1STJk0UHBysXr166YUXXtCZM2fUsGFD/fXXX5o/f76qVKmi6tWrO+COAQAoHCbjepOiAABAsffQQw9px44d1u9NJpNKlSqlOnXq6N5779X9999v7Y3++uuvtWTJEv39998qU6aMmjZtqocfflgPPfSQXnjhBT344IOKiorSiBEjdPDgQfXr10/Tpk1TWlqali9frs8//1yRkZEKCAhQp06d9Oyzz8rf399Bdw4AwM1HoAYAAAAAwA7MoQYAAAAAwA4EagAAAAAA7ECgBgAAAADADgRqAAAAAADsQKAGAAAAAMAOBGoAAAAAAOxAoAYAAAAAwA4EagAAAAAA7ECgBgAAAADADgRqAAAAAADsQKAGAAAAAMAOBGoAAAAAAOxAoAYAAAAAwA4EagAAAAAA7ECgBgAAAADADgRqAAAAAADsQKAGAAAAAMAOBGoAAAAAAOxAoAYAAAAAwA4EagAAcF2GYTi6CiUOrzkAFB8EagBAFg899JCCg4Ot/+rWratmzZqpb9++eu+995SWlmbXNR966CHr98HBwVq8eHFBVrtAde7c2eY1CA4OVqNGjXTHHXdo3rx5SklJKZDnKajXYfHixQoODs6xTHh4uIKDgxUeHi5JmjBhgjp37mw937lzZ02YMMH6/dKlS7Vy5cp81euzzz7L8jo2btxYd911l5YtW6b09PQ8X3P79u3q1q2bGjZsqKFDh+arfvaaMGFClt+Rpk2b6p577tGSJUuUnJyc52tGRkZq+PDhOnPmTIHVc+bMmZo/f74kacyYMapXr54iIiKylDtz5oxatWqlZ599VpK0bds29e7dW6mpqQVWFwBwRm6OrgAAoGiqX7++pk6dKklKT0/XpUuXtHXrVr300kuKiIjQggUL5OJi/+eya9euVVBQUEFV96bo0KGDnnzySev3KSkpCg8P19KlS3XmzBm99tprDqxd3jVo0EBr165V7dq1sz2/ZMkS+fr6Wr9fuHChnnrqqQJ57iVLlqhChQoyDENJSUnavXu3Fi1apOTkZGuIy61XXnlFGRkZWrFihQICAgqkfvaoUKGClixZIknKyMhQfHy8IiIitHz5cv38889699135enpmevr/frrr/rxxx8LrH7btm3Tli1btHnzZknS1KlTtWvXLo0fP17r16+3/qxTU1M1atQolS5dWi+++KIkKSwsTJUrV9bSpUv1zDPPFFidAMDZEKgBANny9fVV06ZNbY517txZNWvW1KxZs/Tll1+qV69edl//2msXReXKlctSz1atWikyMlKfffaZJkyYoIoVKzqmcnbI7md6tfr169+0565Xr56qVKli/b5NmzY6deqU1qxZk+dAHRsbq9DQULVp06aAa5k3Hh4eWV7PDh06qEmTJhoxYoTefvttPfHEE46pnKSXXnpJgwcPlre3tyTJz89Pc+bM0eDBgzVr1iy99NJLkqS5c+dq//79Wr16tc0HKk888YQGDBigBx54oFi1cwAoTAz5BgDkycCBAxUYGKg1a9bYHP/444919913q2HDhurYsaMWL16c43Bey1DnlJQUNW/eXHPmzLE5n5aWptatW1t7zHLzHBMmTNCgQYM0depUhYSEqEePHho5cqTat2+vjIwMm+tPmjRJ3bp1s+s1aNiwoQzD0NmzZyVlftAwe/ZsDRo0SI0bN9akSZMkSdHR0Zo4caI6dOigxo0bq1+/fvruu++yXC8hIUFjx45Vs2bNFBYWphdffFFJSUnW8+np6VqxYoV69uypxo0bq2nTpurfv7+2b9+e5VrffvutunXrpkaNGun+++/Xtm3brOeuHfJ9rauHfFuGjy9ZskTBwcE6cuSIgoODtXbtWpvHnD17VvXq1dOGDRvy8hJKygx4JpPJ5tg///yj0aNHq2XLlmrSpIkGDRqk/fv3S5JOnz6t4OBgnTlzRuvWrbO5l3379unRRx9Vq1atFBISoscff1xHjhzJcu9r1qxRp06dFBISol9++UWSFBERoYEDB6pJkyZq2bKlxo8fr5iYmDzfj0XXrl3VtGlTm9+RG/0MP/vsM02cOFGS1KVLF5uh93n93ZKkH374QYcPH9bdd99tc7xVq1YaMmSIPvvsM23ZskU//PCD3n33XY0ZM0aNGze2KduoUSNVqlRJq1atsvu1AABnR6AGAOSJi4uLwsLCtHfvXutc6uXLl+uFF15QWFiYli1bpgcffFBvvvmmXnjhhRtez9PTU926ddNXX31lsxjTL7/8oosXL6p37955eo6IiAidPXtWr7/+usaMGaN+/fopKirKJkQmJyfr66+/1r333mvXa/DXX39JkqpWrWo99uGHH6pRo0ZaunSp+vXrp/Pnz6tfv36KiIjQqFGjtHjxYlWuXFkjRozIEj7ff/99Xb58WQsWLNBjjz2mjz/+WGPHjrWef/XVV7V06VL95z//0VtvvaWZM2cqNjZWzzzzjE3wljI/KHj44Ye1ePFilSpVSsOGDdO+ffvyfI+W4NyvXz+tXbtWt912m5o0aaL169fblFu3bp18fHx055135ni9jIwMpaWlKS0tTQkJCdq6davWr1+vBx980FomJiZG/fv3159//qkXXnhB8+bNU0ZGhh588EEdO3ZMFStW1Nq1a1WhQgV16NBBa9euVYMGDbR9+3Y98MADkqTZs2frxRdf1NmzZ9W/f38dO3bMph5LlizR+PHjNWXKFDVr1kw7d+7U4MGD5eXlpQULFuj555/Xjh079PDDD9s1D9ri9ttvV2RkpHU+9I1+hh07drT2Zi9ZssQ61cDe360NGzaoadOmCgwMzHLu2WefVb169TR9+nRNnjxZHTt21ODBg7O9Tvfu3fXll1/a/ToAgLNjyDcAIM/Kly+v1NRUxcbGytPT0xoUJk+eLElq27at/P39NXnyZA0ZMkS33XZbjtfr3bu3Pv30U+3atUstWrSQJG3cuFE1a9ZUo0aNFB8fn+vnSEtL04wZM6zzszMyMhQUFKR169YpLCxMkrRlyxYlJiaqT58+OdbLMAybBdguXLigrVu3as2aNerRo4fKlStnPVepUiWbEDx37lzFxMRo8+bNqly5sqTM4cCDBw/WK6+8op49e1rnoNeqVUuvv/66XFxc1KFDB5lMJs2ePVuHDx9WnTp1FB0drVGjRtks6ubp6amnn35ahw4dshl2PH36dHXv3l1S5jzYLl266M0339SiRYtyvNdrWa4ZFBRk/fq+++7T1KlTderUKeuHCevWrdPdd98tLy+vHK93xx13ZDnWqFEjDRo0yPr9u+++q9jYWH300UfW16x9+/bq0aOHFi5cqEWLFqlp06by8PCwGY4/b9483XrrrVqxYoVcXV0lZbaPO+64Q4sWLdLChQutzzFgwADr62N5bI0aNbR8+XLrY5s0aaK7775bn376qU3gz4vy5ctLks6fP6/KlSvn6mdYrVo1SVeGx+el3V9r+/btWXqnLTw8PPTyyy+rd+/e8vDw0OzZs7OMFLBo1KiRli1bpmPHjqlWrVp2vRYA4MzooQYA5JmlJ9lkMmnPnj1KTk5W586drT2QaWlp1tWjLcNqc9KyZUtVqlRJGzdulJS5+Ne3335r7Z3Oy3P4+/vbLHbm4uKie++9V9988421N/fzzz9XmzZtbrgo2rp169SgQQPrv/bt22vatGnq0qWLdcE2i3r16tl8v2PHDjVr1swaDC169eqlc+fO6fjx49Zj3bt3t1ngzdLbu3PnTkmZoW/QoEGKiYlRRESEPv30U2svt9lstj7O3d3dpqfY09NT7du3t14nvyzB2dJLvXv3bp04cSJXPf1vvPGGPvnkE33yySf68MMPNW3aNEVHR6t///5KSEiQlLmIVr169RQYGGj9Gbu4uKh9+/b69ddfs71uYmKi9u3bp7vuussaiKXM4eSdOnXSjh07bMpf/XNKSkrS77//rg4dOlg/PElLS1PVqlVVq1atXLXd67n6d0TK/c/wavb+biUmJurChQs2c9avtXnzZplMJpnNZn3++efXLWe5xunTp29wxwBQMtFDDQDIs6ioKHl5ecnf31+xsbGSpOHDh2dbNjo6+obXM5lMuueee/Txxx9r8uTJ+t///qfExETdc889kpSn5yhVqlSW8/fdd5+WLVumb775Rq1bt9a2bdv06quv3rBenTp10ogRI6x19Pb2VuXKlbPtjfXx8bH5/tKlSzZDwi0sPZdxcXHWYxUqVLApY1m52lJm3759mj59uvbt2ydvb2/Vrl1blSpVkmS7Z3HZsmWzrLweEBBg81z54evrq+7du2vDhg166qmntG7dOtWoUUPNmjW74WPr1KljE/BatGihOnXqaMCAAfr44481ZMgQxcbG6uTJk2rQoEG210hKSrIusGURHx8vwzCsr+vVypcvr/j4eJtjV/+c4uLilJGRoTfffFNvvvlmlsfnZYXua0VFRUmSdch1bn+GV7P3d8tyz9e2SYvw8HAtW7ZMw4YN0/79+7VgwQLdfvvtWT4UkmR9va99HQEAmQjUAIA8SUtLU3h4uEJCQuTq6io/Pz9JmXNEq1evnqV8dkEnO71799by5csVHh6uTZs2KTQ01Nq7m9/nqFq1qlq2bKmvvvpKsbGx8vX1VdeuXW9YJ39/fzVq1ChX9b9WmTJldO7cuSzHLcfKli1rPWYJTteWCQgIUEJCgoYOHarg4GDrMHgXFxf9+OOP1u2QLCzh8urhu+fPn7cZmp5f9913nz7//HPt3btXmzdv1qOPPmr3tSyv7YkTJyRJpUuXVsuWLfXcc89lW97DwyPLsdKlS8tkMun8+fNZzp07d07+/v7Xff5SpUrJZDJp8ODB2Q6Pvja858Wvv/6qW2+9VYGBgXn6GV7N3nZvaVvZfZASExOjsWPHKjg4WE8//bQuXryoe+65R2PGjNFnn32W5cOiS5cu2VwTAGCLId8AgDxZu3atzp07Z10EqkmTJnJ3d1dUVJQaNWpk/efm5qbXXnst10NFa9WqpQYNGmjjxo368ccfbbbkKojn6Nevn3799Vd9+eWX6tGjR756H3MjNDRUe/bssS5KZbFhwwZVqFBBt956q/XY1q1bbcps3LhRJpNJLVu21PHjxxUbG6uHH35YtWvXtvZAWx5z9erlSUlJNit/X758WT/88INatWpl1z1kt894aGioqlevrrlz5yo+Pt46LN8ee/fulSRrWGzZsqX++usv1ahRw+bnvH79en3yySc2Q7otfHx81LBhQ3311Vc2K1/Hx8frhx9+UPPmza/7/L6+vqpfv76OHz9u83y33XabFi9efN3V0G/khx9+0L59+6y/I7n9GV77etvb7j08PFShQgXrKvQWhmFo4sSJiouL07x58+Th4aHAwEBNmzZNx44dy7LSvnSlp93Smw4AsEUPNQAgWwkJCfrtt98kZf7Bf/HiRf38889au3atevXqZZ2rW7ZsWQ0dOlQLFy5UQkKCWrVqpaioKC1cuFAmk0l169bN9XP27t1bc+bMkZubm83CUQXxHN26ddPMmTO1d+/eXK0+nl9DhgzRhg0bNHjwYD311FPy9/fXunXrtH37ds2ePdsmPO3bt0+TJk1Sz549tW/fPi1atEj9+vVT9erVFR8fL19fXy1btkxubm5yc3PT5s2b9cknn0iSzSrf7u7uev755zV69Gj5+vpqxYoVSk5Otq4YnVd+fn7avXu3du7cqRYtWlh7vu+77z7NmzdP7du3z3YV6ewcOHDA2ouckZGhY8eOafHixapQoYJ1DvbgwYO1fv16DR48WI888ojKli2rTZs26b///a91S6nsjBkzRo8++qiGDx+uAQMGKDU1VStWrJDZbLYO2b+e0aNHa/jw4RozZox69eql9PR0vf322/r9999v+LqZzWbr74hhGIqLi1NERITee+89tWrVSgMHDpQk1ahRI1c/Q0uP9JYtW9S+fXvVqlXL7nZ/++23a/fu3TbH3nnnHf3www+aOnWqzQJjPXr00Pfff6/Vq1erQ4cO6tixo/Xcrl27VKVKFdWoUSPH1wIASioCNQAgW/v379d//vMfSZnzh0uVKqU6depo2rRpuv/++23KPvvss6pQoYJWr16tt956S2XKlFFYWJhGjx6t0qVL5/o5e/bsqVdeeUWdOnXK8rj8Poenp6dat26t48ePZ9lv92aoUKGCPvroI82bN08vvviiUlNTVbduXS1dulRdunSxKTtixAj98ccfevzxx1W6dGkNHTpUTz31lKTMIc1Lly7VK6+8omeeeUalSpVSvXr19MEHH2jYsGGKiIiwLlJVrlw5jRkzRq+99prOnTunJk2a6IMPPlDNmjXtuofHH39cS5cu1bBhw7Rp0yZrL2WHDh00b9489e3bN9fXstyPJLm5uals2bJq1aqVnnnmGeuwbMv+5vPmzdO0adOUkpKi6tWra9asWerXr991rx0WFqZVq1Zp0aJFGj16tDw8PNSiRQvNmTPnhivMt23bVitXrtSSJUs0cuRIubu7q0GDBlq1apXN6unZOXfunPV3RMrsLa9Ro4ZGjhyphx56SO7u7pJy/zNs1aqV2rRpo3nz5mnbtm1asWKF3e2+W7du+uKLLxQVFaXAwED98ccfmjdvnjp16qQBAwZkKT916lTt2rVLzz//vDZs2GAdTv7TTz/ZfLgFALBlMq63EgYAAE4kOTlZHTp00JNPPmmzVRPybsWKFdbezuzmNcPxDMNQr1691K1bN5sPM/IiIiJCjzzyiL799ltVrFixgGsIAM6BHmoAgFM7c+aMPv/8c/36668ymUy67777HF2lYuvzzz/X4cOHtXr1aj355JOE6SLMZDJp3Lhxev755zV48GD5+vrm+RpvvfWWBg0aRJgGgBywKBkAwKm5uLjo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r3Hjxhnh4eHGiBEjrlrXyJEjjQ4dOhjx8fHGH3/8Ydx///3Gww8/bH09OTnZuPXWW41nnnnG2Ldvn/Hrr78arVq1Ml599dVCx122bJnRuHFj48svvzT27dtnxMXFGc2bN89Tb0pKitGvXz8jPDzcWLp0aRF+kqWTu/VHjrVr1xqNGjUy7rjjjjyvPf/880ZcXJyRlJSU6w+uj6v22tmzZ3P1wbFjx4yOHTsajz76qJGZmVnguByLro279UcOjkXOy1V78sCBA0bDhg2N6dOnG0eOHDG++uoro3HjxsbChQsLHXf69OlGixYtjB9++MHYtWuX0a9fP6Njx45GRkZGrvUSExONbt26GeHh4cb69euL8qMsldytP3IsXLjQiIiIMGJjY/O81qNHD2Py5Mm5jlf5vZ+iIFDDaSQkJBjh4eHGpk2brMssFovRoUMH45133jFefvllo0ePHrm2GTZsmNGvXz/DMAzj119/NcLDw43ExETr6+np6UaTJk2Mzz77LNd2P//8s3Hrrbca995771X/wScmJhoRERHGjz/+aF128OBBIzw83NiyZYthGIYxbdo0o02bNkZ6erp1nU8//dTo1q2bYbFYChy7Y8eOxvjx463fZ2ZmGrfffrsxc+ZM67LvvvvOaNu2rfV/CO76IdYd++PixYvGiBEjjMjISKNr1675foi95557jA8//LDQGnFtXLnX/umtt94ybrnllqt+SOBYVHTu2B8ci5ybK/fkhx9+aDRv3jzXdgMHDjQGDBhQ4LgZGRlG06ZNjY8//ti67MKFC0bjxo2NFStWWJd99tlnRvPmzd0+ULtbf+SMPWDAACMqKsq4++678wRqi8ViREVFGWvWrCl0nKJiyjecRvny5TV79mw1atTIusxkMslkMiklJUWbNm1Sy5Ytc21zyy23aPPmzTIMQ3Xr1tXs2bNVpUoV6+seHldaPCUlxbosOTlZo0aN0rhx41S+fPmr1rV582brvnLUrFlTVapUsU6RW7dune688075+vpa1+nZs6eWLVsmk8mU77hnz55VQkJCrvfk5eWlZs2a5Zp69+2336pXr15avHjxVWstzdytPyTp2LFjOnnypD777DN16NAhz+tms1kJCQmqVavWVetE0blyr/3d/v37NX/+fI0cOVIhISEFjsux6Nq4W39IHIucnSv3ZIUKFXT+/HmtXLlShmFoz5492rx5s5o0aVLguLt379bly5dzvaeyZcuqQYMGuXp97dq1Gjp0qKZOnXrVWkszd+sPSfrrr7/k7e2t5cuX57vukSNHlJqaarNjFoEaTqNs2bK6/fbb5ePjY132zTff6PDhw2rdurUSExMVGhqaa5vKlSsrLS1N586dU6VKlXT77bfnen3BggVKT0/XbbfdZl320ksv6Y477ijydRKnTp1S+fLlc4WhnH0nJiZKunJ9bOXKlfXmm2+qbdu2uvPOOzV+/HhlZGQUOG7OtlWrVi1wXEl64403NGDAgFw/F3fkbv0hSREREZo3b57q16+f7+v79+9Xdna2vvnmG911111q27at4uLilJSUVKTakT9X7rW/mzZtmsLDw3XfffcVOi7Homvjbv0hcSxydq7ck/fcc4969uypuLg4RUZGqmvXrrrtttv09NNPFzhuUY9Zs2bNUq9evQr9xbU7cLf+kK7cL2L69OmqVq1avq/v3bvX+j7atWunDh06aOzYsbp48WKRav8nAjWc1pYtWzRq1Ch17NhRbdu2VXp6ep4Pcjnfm83mPNuvXbtWkyZN0uOPP269McrixYt14MABjRo1qsh1pKWl5fsB0tfX1xqILl26pPfff18ZGRl69913FRcXpxUrVmj06NGFjvv395DfuChYae+Posj5H4K/v7+mTp2q119/XQcPHtSjjz6q9PT06xob/8+Vei3H0aNHtXbtWj3zzDNFGvfv76GwcZFXae+PouBY5FxcqSfPnj2r48ePa/Dgwfr888/1+uuv66efftL06dMLHffv7yG/cVGw0t4fRbF37155eHiocuXKmjlzpkaOHKl169bp2WeflcViuebxvK6rGsBOvv32Ww0fPlzR0dGaOHGipCv/wP75Dzvne39//1zLP/nkE40bN05du3bViy++KEk6ePCgJkyYoDlz5iggICDf/fbv3986BUWSXnvtNfn5+eV7QMnIyLDu18vLSzVr1tSYMWMkSQ0bNlR2draGDBmikSNH6rPPPtOsWbOs23bp0kUPPvhgrveQ37jInzv0x9ixY6/6c7j//vvVpk2bXNM169atqzZt2uj7779Xp06drjoGCudqvZZj+fLlqlChQp7puTNnzuRYZEPu0B8ci1yLq/XkSy+9pKpVq1p/udOgQQMZhqExY8YoNjZW77zzjlasWGHddsCAAapZs6b1Pfj5+eU7LvLnDv1xtbPXkvTMM8+oT58+1qnp4eHhqlSpkh588EHt2LHjqlPK/4lADaezcOFCvf7667r77rv19ttvW397VbVq1TzTx5KSkhQQEKCgoCDrsgkTJuiDDz5Q3759NWLECOtUn1WrVuny5cvq27evdd309HRt2bJF33zzjbZu3arXX38912/TK1SooJ9//lnnz5+X2WzO9Zu0pKQk6/UkoaGhqlu3bq7acr4/fvy4evXqpXvuucf6WmBgYK5xateune+4yMvd+uNq/nntY+XKlRUcHJzvFE9cG1fstRzffvut7r33Xut1bjk4FtmOu/XH1XAscjxX7MnNmzdbg1mOqKgoZWVl6dixY3r++ef1xBNPWF8rV66cjhw5Yh2nevXqucblUW0Fc5f+KAoPD48813nnfC5LTEwkUMO1LVq0SOPGjdMjjzyil156Kdd1L82aNdPGjRtzrb9+/XpFR0dbPxTk/GMfMWKE+vXrl2vd2NhYdenSJdey4cOHKzQ0VMOHD5ekfD883nzzzbJYLNq8ebP1pg2HDh3SqVOnFBMTI0mKiYnR9u3bZRiGtea9e/fK09NTYWFhCg4OVnBwcJ6xa9asqQ0bNljHzcrK0qZNm9SnT58i/8zcibv1x9VMmTJFq1ev1urVq63jHjt2TOfOnVOdOnWueTz8P1ftNenKJQa7du3SkCFD8ozBscg23K0/roZjkeO5ak9WqVJFe/bsybXdnj17ZDKZdNNNN6lcuXKqUKFCrtcDAgIUGBioDRs2WAN1SkqKdu7cqdjY2KL9wNyMO/VHUbz44otKSkrSRx99ZF22Y8cOSSreMcsm9woHbODgwYNGZGSkMXDgwDzPsUxJSTH27t1rREZGGhMmTDD2799vzJkzJ9dz8tavX2+Eh4cb48aNy7P9pUuX8t1nbGxskZ6TN2zYMKNdu3bG+vXrrc/J+/st+A8cOGA0adLEePnll42DBw8aP//8s9GmTRtj5MiRhY67ZMkSo3HjxsayZcusz35t0aJFgY8wcedH1bhjf/zdtGnT8jyqZseOHUZkZKTxyiuvGAcPHjQ2btxo3H///UavXr0KfRwXCufKvWYYhhEfH5/nESdXw7Go6NyxP/6OY5HzceWeXLx4sdGgQQNj3rx5xpEjR4y1a9cat912m/Haa68VOu7kyZON5s2bG99++22u51CbzeY86x49etStH5vljv3xdyNGjMhzHPz222+N8PBwY/r06cbhw4eNH3/80WjXrp0xbNiwIo/7d5yhhtP45ptvlJmZqbVr12rt2rW5XuvWrZveeustzZgxQxMmTNC8efMUFhamCRMmWH+rtXLlSklX7ti3YMGCXNs/99xzGjRoULFrGzdunN544w0999xzkqQ2bdrkuqFUrVq1NH/+fI0fP1733XefgoKC1LVrVw0dOrTQcR988EFdvHhR77zzjs6fP6+GDRvqww8/vOojTNyRO/bH1TRs2FDvv/++pk6dqu7du8vHx0ft27fPNRUL186Ve02SderetZxp5FhUdO7YH1fDscixXLknH3roIfn6+urDDz/U5MmTVaVKFfXp00dPPvlkoeMOHjxYWVlZGj16tNLT0xUTE6M5c+bI29u72LWWVu7YH1fTvn17vfPOO5o9e7bef/99BQUFqUuXLvnO3CkKk2EYxnVVBAAAAACAG+KxWQAAAAAAFAOBGgAAAACAYiBQAwAAAABQDARqAAAAAACKgUANAAAAAEAxEKgBAAAAACgGAjUAAAAAAMVAoAYAANfEMAxHlwAAgFMgUAMAUIo98sgjqlevnvVPRESEmjZtqu7du2v+/PnKysq6pvH27dun3r1726laAABci5ejCwAAAPbVoEEDvfrqq5Kk7OxsXbhwQT///LPefPNNbdq0Se+88448PIr2O/bVq1dr69at9iwXAACXQaAGAKCUCwwMVFRUVK5l7dq1U61atfT6669r5cqV6tq1q2OKAwDAhTHlGwAANxUbG6sqVapo8eLFkqT09HRNmjRJHTt2VMOGDRUdHa2+fftq165dkqTp06fr3XfflSTVq1dP06dPlyRZLBbNnj1bd955pxo2bKi77rpLCxYscMybAgCgBHGGGgAAN+Xh4aGWLVvqq6++UlZWll588UVt2rRJw4YNU/Xq1XX48GFNnTpVL7zwgr766iv17NlTiYmJ+vzzz7VkyRKFhoZKksaMGaNly5ZpwIABatq0qeLj4/XGG28oJSVFAwcOdPC7BADAfgjUAAC4sYoVKyozM1Pnz5/X5cuXNXr0aHXq1EmS1Lx5c126dElvvfWWzpw5o9DQUGuIzplCfujQIX366acaNmyYnnrqKUlSq1atZDKZNGvWLPXp00fly5d3yHsDAMDemPINAIAby3kElslk0pw5c9SpUyedOnVK69ev1+LFi/XDDz9Iksxmc77br1+/XoZhqF27dsrKyrL+adeunTIyMrR58+YSey8AAJQ0zlADAODGTp06JT8/PwUHB+uXX37RG2+8oYMHD6pMmTKKiIhQQECApIKfPX3+/HlJ0r333lvg+AAAlFYEagAA3FRWVpY2bNig6OhoHT9+XAMHDlSHDh00a9YsVatWTSaTSR9//LF++eWXAscoW7asJGnevHkqU6ZMntdvuOEGu9UPAICjMeUbAAA3tWTJEp0+fVq9e/fWn3/+qYyMDD311FOqXr26TCaTJFnDdM4Z6n8+r7pZs2aSpHPnzqlRo0bWP8nJyZo6dar1DDYAAKURZ6gBACjlLl26pG3btkm68oirc+fOad26dVqyZIm6du2qjh076vDhw/Ly8tKECRPUr18/mc1mLVu2TD/++KMkKTU1VdL/n5FeuXKlmjRponr16qlr1656+eWXdfz4cTVs2FCHDh3SlClTFBYWpho1ajjgHQMAUDJMRkEXRQEAAJf3yCOPaOPGjdbvTSaTypQpo/DwcHXr1k09e/a0no1evXq13n33XR05ckTlypVTVFSUHn30UT3yyCN6+eWX9fDDD+vUqVMaOHCgdu/erR49emjMmDHKysrSrFmz9MUXXygxMVEVKlTQHXfcoSFDhig4ONhB7xwAAPsjUAMAAAAAUAxcQw0AAAAAQDEQqAEAAAAAKAYCNQAAAAAAxUCgBgAAAACgGAjUAAAAAAAUA4EaAAAAAIBiIFADAAAAAFAMBGoAAAAAAIqBQA0AAAAAQDEQqAEAAAAAKAYCNQAAAAAAxfB//IsDidsWjHoAAAAASUVORK5CYII=", | |
| "text/plain": [ | |
| "<Figure size 1000x800 with 2 Axes>" | |
| ] | |
| }, | |
| "metadata": {}, | |
| "output_type": "display_data" | |
| } | |
| ], | |
| "source": [ | |
| "import matplotlib.pyplot as plt\n", | |
| "import seaborn as sns\n", | |
| "\n", | |
| "sns.set(style=\"whitegrid\")\n", | |
| "\n", | |
| "fig, axes = plt.subplots(nrows=2, ncols=1, figsize=(10, 8)) # Adjust the figure size as necessary\n", | |
| "\n", | |
| "sns.lineplot(ax=axes[0], data=delivery_probabilities[\"probability_on_date\"]).set_title(\n", | |
| " \"Delivery Probability on Date (X)\"\n", | |
| ")\n", | |
| "axes[0].set_ylabel(\"Probability\")\n", | |
| "axes[0].set_xlabel(\"Date\")\n", | |
| "\n", | |
| "sns.lineplot(ax=axes[1], data=delivery_probabilities[\"probability_before_date\"]).set_title(\n", | |
| " \"Delivery Probability Before Date (X)\"\n", | |
| ")\n", | |
| "axes[1].set_ylabel(\"Probability\")\n", | |
| "axes[1].set_xlabel(\"Date\")\n", | |
| "\n", | |
| "plt.tight_layout()\n", | |
| "\n", | |
| "plt.show()" | |
| ] | |
| }, | |
| { | |
| "cell_type": "markdown", | |
| "id": "06bb507b", | |
| "metadata": {}, | |
| "source": [ | |
| "<a id=\"modeling\"></a>\n", | |
| "# Determining Probability Distributions\n", | |
| "\n", | |
| "Unfortunately, the one paper that has the parameters for the due date was buried [here](https://www.sciencedirect.com/science/article/pii/S0029784400011315?casa_token=yV-QZInYkl8AAAAA:0U_Z2dT-r0y1etlX8hRG5ulyrjtzoVXRXIlvJkcSyXhtllUlkhWPNr5f3MJL0LMFzHZv5TwsN4Q), behind a paywall.\n", | |
| "\n", | |
| "So, we used the calculator [here](https://datayze.com/labor-probability-calculator) and *fit* the parameters after the due date.\n", | |
| "\n", | |
| "Kids, this is not great data science, but it works nicely. We:\n", | |
| "1. Parse the data\n", | |
| "2. Resample\n", | |
| "3. Use sklearn.skewnorm.fit()\n", | |
| "4. Return the parameters\n", | |
| "\n", | |
| "This is a dumb way to get it to use `sklearn.skewnorm.fit()` -- in reality we can optimize it to fit the PDF curve. Or read the library more for the right function. That said, the code here is simple\n", | |
| "and easy. The lesson is that most of what we call data science is often clever hacks to get the numbers to look good, and they work!" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 35, | |
| "id": "82d96ff4", | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "data": { | |
| "image/svg+xml": [ | |
| "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n", | |
| "<!DOCTYPE svg PUBLIC \"-//W3C//DTD SVG 1.1//EN\"\n", | |
| " \"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd\">\n", | |
| "<!-- Generated by graphviz version 12.0.0 (20240704.0754)\n", | |
| " -->\n", | |
| "<!-- Pages: 1 -->\n", | |
| "<svg width=\"696pt\" height=\"318pt\"\n", | |
| " viewBox=\"0.00 0.00 695.75 317.60\" xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n", | |
| "<g id=\"graph0\" class=\"graph\" transform=\"scale(1 1) rotate(0) translate(4 313.6)\">\n", | |
| "<polygon fill=\"white\" stroke=\"none\" points=\"-4,4 -4,-313.6 691.75,-313.6 691.75,4 -4,4\"/>\n", | |
| "<g id=\"clust1\" class=\"cluster\">\n", | |
| "<title>cluster__legend</title>\n", | |
| "<polygon fill=\"#ffffff\" stroke=\"black\" points=\"8,-196.8 8,-271.8 92.85,-271.8 92.85,-196.8 8,-196.8\"/>\n", | |
| "<text text-anchor=\"middle\" x=\"50.42\" y=\"-254.5\" font-family=\"Helvetica,sans-Serif\" font-size=\"14.00\">Legend</text>\n", | |
| "</g>\n", | |
| "<!-- raw_probabilities -->\n", | |
| "<g id=\"node1\" class=\"node\">\n", | |
| "<title>raw_probabilities</title>\n", | |
| "<path fill=\"#b4d8e4\" stroke=\"black\" d=\"M241.2,-186.6C241.2,-186.6 131.85,-186.6 131.85,-186.6 125.85,-186.6 119.85,-180.6 119.85,-174.6 119.85,-174.6 119.85,-135 119.85,-135 119.85,-129 125.85,-123 131.85,-123 131.85,-123 241.2,-123 241.2,-123 247.2,-123 253.2,-129 253.2,-135 253.2,-135 253.2,-174.6 253.2,-174.6 253.2,-180.6 247.2,-186.6 241.2,-186.6\"/>\n", | |
| "<text text-anchor=\"start\" x=\"130.65\" y=\"-163.5\" font-family=\"Helvetica,sans-Serif\" font-weight=\"bold\" font-size=\"14.00\">raw_probabilities</text>\n", | |
| "<text text-anchor=\"start\" x=\"152.4\" y=\"-135.5\" font-family=\"Helvetica,sans-Serif\" font-style=\"italic\" font-size=\"14.00\">DataFrame</text>\n", | |
| "</g>\n", | |
| "<!-- resampled -->\n", | |
| "<g id=\"node5\" class=\"node\">\n", | |
| "<title>resampled</title>\n", | |
| "<path fill=\"#b4d8e4\" stroke=\"black\" d=\"M360.05,-186.6C360.05,-186.6 294.2,-186.6 294.2,-186.6 288.2,-186.6 282.2,-180.6 282.2,-174.6 282.2,-174.6 282.2,-135 282.2,-135 282.2,-129 288.2,-123 294.2,-123 294.2,-123 360.05,-123 360.05,-123 366.05,-123 372.05,-129 372.05,-135 372.05,-135 372.05,-174.6 372.05,-174.6 372.05,-180.6 366.05,-186.6 360.05,-186.6\"/>\n", | |
| "<text text-anchor=\"start\" x=\"293\" y=\"-163.5\" font-family=\"Helvetica,sans-Serif\" font-weight=\"bold\" font-size=\"14.00\">resampled</text>\n", | |
| "<text text-anchor=\"start\" x=\"316.62\" y=\"-135.5\" font-family=\"Helvetica,sans-Serif\" font-style=\"italic\" font-size=\"14.00\">List</text>\n", | |
| "</g>\n", | |
| "<!-- raw_probabilities->resampled -->\n", | |
| "<g id=\"edge5\" class=\"edge\">\n", | |
| "<title>raw_probabilities->resampled</title>\n", | |
| "<path fill=\"none\" stroke=\"black\" d=\"M253.58,-154.8C259.29,-154.8 265.03,-154.8 270.65,-154.8\"/>\n", | |
| "<polygon fill=\"black\" stroke=\"black\" points=\"270.44,-158.3 280.44,-154.8 270.44,-151.3 270.44,-158.3\"/>\n", | |
| "</g>\n", | |
| "<!-- scale -->\n", | |
| "<g id=\"node2\" class=\"node\">\n", | |
| "<title>scale</title>\n", | |
| "<path fill=\"#b4d8e4\" stroke=\"black\" d=\"M650.62,-309.6C650.62,-309.6 619.28,-309.6 619.28,-309.6 613.28,-309.6 607.28,-303.6 607.28,-297.6 607.28,-297.6 607.28,-258 607.28,-258 607.28,-252 613.28,-246 619.28,-246 619.28,-246 650.62,-246 650.62,-246 656.62,-246 662.62,-252 662.62,-258 662.62,-258 662.62,-297.6 662.62,-297.6 662.62,-303.6 656.62,-309.6 650.62,-309.6\"/>\n", | |
| "<text text-anchor=\"start\" x=\"618.08\" y=\"-286.5\" font-family=\"Helvetica,sans-Serif\" font-weight=\"bold\" font-size=\"14.00\">scale</text>\n", | |
| "<text text-anchor=\"start\" x=\"622.2\" y=\"-258.5\" font-family=\"Helvetica,sans-Serif\" font-style=\"italic\" font-size=\"14.00\">float</text>\n", | |
| "</g>\n", | |
| "<!-- a -->\n", | |
| "<g id=\"node3\" class=\"node\">\n", | |
| "<title>a</title>\n", | |
| "<path fill=\"#b4d8e4\" stroke=\"black\" d=\"M649.95,-227.6C649.95,-227.6 619.95,-227.6 619.95,-227.6 613.95,-227.6 607.95,-221.6 607.95,-215.6 607.95,-215.6 607.95,-176 607.95,-176 607.95,-170 613.95,-164 619.95,-164 619.95,-164 649.95,-164 649.95,-164 655.95,-164 661.95,-170 661.95,-176 661.95,-176 661.95,-215.6 661.95,-215.6 661.95,-221.6 655.95,-227.6 649.95,-227.6\"/>\n", | |
| "<text text-anchor=\"start\" x=\"631.2\" y=\"-204.5\" font-family=\"Helvetica,sans-Serif\" font-weight=\"bold\" font-size=\"14.00\">a</text>\n", | |
| "<text text-anchor=\"start\" x=\"622.2\" y=\"-176.5\" font-family=\"Helvetica,sans-Serif\" font-style=\"italic\" font-size=\"14.00\">float</text>\n", | |
| "</g>\n", | |
| "<!-- loc -->\n", | |
| "<g id=\"node4\" class=\"node\">\n", | |
| "<title>loc</title>\n", | |
| "<path fill=\"#b4d8e4\" stroke=\"black\" d=\"M649.95,-145.6C649.95,-145.6 619.95,-145.6 619.95,-145.6 613.95,-145.6 607.95,-139.6 607.95,-133.6 607.95,-133.6 607.95,-94 607.95,-94 607.95,-88 613.95,-82 619.95,-82 619.95,-82 649.95,-82 649.95,-82 655.95,-82 661.95,-88 661.95,-94 661.95,-94 661.95,-133.6 661.95,-133.6 661.95,-139.6 655.95,-145.6 649.95,-145.6\"/>\n", | |
| "<text text-anchor=\"start\" x=\"625.2\" y=\"-122.5\" font-family=\"Helvetica,sans-Serif\" font-weight=\"bold\" font-size=\"14.00\">loc</text>\n", | |
| "<text text-anchor=\"start\" x=\"622.2\" y=\"-94.5\" font-family=\"Helvetica,sans-Serif\" font-style=\"italic\" font-size=\"14.00\">float</text>\n", | |
| "</g>\n", | |
| "<!-- distribution_params -->\n", | |
| "<g id=\"node6\" class=\"node\">\n", | |
| "<title>distribution_params</title>\n", | |
| "<path fill=\"#b4d8e4\" stroke=\"black\" d=\"M541.15,-186.6C541.15,-186.6 413.05,-186.6 413.05,-186.6 407.05,-186.6 401.05,-180.6 401.05,-174.6 401.05,-174.6 401.05,-135 401.05,-135 401.05,-129 407.05,-123 413.05,-123 413.05,-123 541.15,-123 541.15,-123 547.15,-123 553.15,-129 553.15,-135 553.15,-135 553.15,-174.6 553.15,-174.6 553.15,-180.6 547.15,-186.6 541.15,-186.6\"/>\n", | |
| "<text text-anchor=\"start\" x=\"411.85\" y=\"-163.5\" font-family=\"Helvetica,sans-Serif\" font-weight=\"bold\" font-size=\"14.00\">distribution_params</text>\n", | |
| "<text text-anchor=\"start\" x=\"466.6\" y=\"-135.5\" font-family=\"Helvetica,sans-Serif\" font-style=\"italic\" font-size=\"14.00\">dict</text>\n", | |
| "</g>\n", | |
| "<!-- resampled->distribution_params -->\n", | |
| "<g id=\"edge6\" class=\"edge\">\n", | |
| "<title>resampled->distribution_params</title>\n", | |
| "<path fill=\"none\" stroke=\"black\" d=\"M372.52,-154.8C377.97,-154.8 383.67,-154.8 389.48,-154.8\"/>\n", | |
| "<polygon fill=\"black\" stroke=\"black\" points=\"389.24,-158.3 399.24,-154.8 389.24,-151.3 389.24,-158.3\"/>\n", | |
| "</g>\n", | |
| "<!-- distribution_params->scale -->\n", | |
| "<g id=\"edge2\" class=\"edge\">\n", | |
| "<title>distribution_params->scale</title>\n", | |
| "<path fill=\"none\" stroke=\"black\" d=\"M518.64,-186.8C543.16,-206.15 574.16,-230.61 597.84,-249.3\"/>\n", | |
| "<polygon fill=\"black\" stroke=\"black\" points=\"595.64,-252.03 605.66,-255.47 599.98,-246.53 595.64,-252.03\"/>\n", | |
| "</g>\n", | |
| "<!-- distribution_params->a -->\n", | |
| "<g id=\"edge3\" class=\"edge\">\n", | |
| "<title>distribution_params->a</title>\n", | |
| "<path fill=\"none\" stroke=\"black\" d=\"M553.29,-174.58C568.34,-178.54 583.52,-182.53 596.6,-185.97\"/>\n", | |
| "<polygon fill=\"black\" stroke=\"black\" points=\"595.46,-189.29 606.02,-188.45 597.24,-182.52 595.46,-189.29\"/>\n", | |
| "</g>\n", | |
| "<!-- distribution_params->loc -->\n", | |
| "<g id=\"edge4\" class=\"edge\">\n", | |
| "<title>distribution_params->loc</title>\n", | |
| "<path fill=\"none\" stroke=\"black\" d=\"M553.29,-135.02C568.34,-131.06 583.52,-127.07 596.6,-123.63\"/>\n", | |
| "<polygon fill=\"black\" stroke=\"black\" points=\"597.24,-127.08 606.02,-121.15 595.46,-120.31 597.24,-127.08\"/>\n", | |
| "</g>\n", | |
| "<!-- distribution -->\n", | |
| "<g id=\"node7\" class=\"node\">\n", | |
| "<title>distribution</title>\n", | |
| "<path fill=\"#b4d8e4\" stroke=\"black\" d=\"M675.75,-63.6C675.75,-63.6 594.15,-63.6 594.15,-63.6 588.15,-63.6 582.15,-57.6 582.15,-51.6 582.15,-51.6 582.15,-12 582.15,-12 582.15,-6 588.15,0 594.15,0 594.15,0 675.75,0 675.75,0 681.75,0 687.75,-6 687.75,-12 687.75,-12 687.75,-51.6 687.75,-51.6 687.75,-57.6 681.75,-63.6 675.75,-63.6\"/>\n", | |
| "<text text-anchor=\"start\" x=\"597.83\" y=\"-40.5\" font-family=\"Helvetica,sans-Serif\" font-weight=\"bold\" font-size=\"14.00\">distribution</text>\n", | |
| "<text text-anchor=\"start\" x=\"592.95\" y=\"-12.5\" font-family=\"Helvetica,sans-Serif\" font-style=\"italic\" font-size=\"14.00\">rv_continuous</text>\n", | |
| "</g>\n", | |
| "<!-- distribution_params->distribution -->\n", | |
| "<g id=\"edge7\" class=\"edge\">\n", | |
| "<title>distribution_params->distribution</title>\n", | |
| "<path fill=\"none\" stroke=\"black\" d=\"M518.64,-122.8C538.69,-106.98 563.06,-87.75 584.22,-71.05\"/>\n", | |
| "<polygon fill=\"black\" stroke=\"black\" points=\"586.2,-73.94 591.88,-65 581.86,-68.45 586.2,-73.94\"/>\n", | |
| "</g>\n", | |
| "<!-- raw_data -->\n", | |
| "<g id=\"node8\" class=\"node\">\n", | |
| "<title>raw_data</title>\n", | |
| "<path fill=\"#b4d8e4\" stroke=\"black\" d=\"M78.85,-186.6C78.85,-186.6 22,-186.6 22,-186.6 16,-186.6 10,-180.6 10,-174.6 10,-174.6 10,-135 10,-135 10,-129 16,-123 22,-123 22,-123 78.85,-123 78.85,-123 84.85,-123 90.85,-129 90.85,-135 90.85,-135 90.85,-174.6 90.85,-174.6 90.85,-180.6 84.85,-186.6 78.85,-186.6\"/>\n", | |
| "<text text-anchor=\"start\" x=\"20.8\" y=\"-163.5\" font-family=\"Helvetica,sans-Serif\" font-weight=\"bold\" font-size=\"14.00\">raw_data</text>\n", | |
| "<text text-anchor=\"start\" x=\"42.92\" y=\"-135.5\" font-family=\"Helvetica,sans-Serif\" font-style=\"italic\" font-size=\"14.00\">str</text>\n", | |
| "</g>\n", | |
| "<!-- raw_data->raw_probabilities -->\n", | |
| "<g id=\"edge1\" class=\"edge\">\n", | |
| "<title>raw_data->raw_probabilities</title>\n", | |
| "<path fill=\"none\" stroke=\"black\" d=\"M91.3,-154.8C96.71,-154.8 102.4,-154.8 108.2,-154.8\"/>\n", | |
| "<polygon fill=\"black\" stroke=\"black\" points=\"107.92,-158.3 117.92,-154.8 107.92,-151.3 107.92,-158.3\"/>\n", | |
| "</g>\n", | |
| "<!-- function -->\n", | |
| "<g id=\"node9\" class=\"node\">\n", | |
| "<title>function</title>\n", | |
| "<path fill=\"#b4d8e4\" stroke=\"black\" d=\"M72.85,-241.1C72.85,-241.1 28,-241.1 28,-241.1 22,-241.1 16,-235.1 16,-229.1 16,-229.1 16,-216.5 16,-216.5 16,-210.5 22,-204.5 28,-204.5 28,-204.5 72.85,-204.5 72.85,-204.5 78.85,-204.5 84.85,-210.5 84.85,-216.5 84.85,-216.5 84.85,-229.1 84.85,-229.1 84.85,-235.1 78.85,-241.1 72.85,-241.1\"/>\n", | |
| "<text text-anchor=\"middle\" x=\"50.42\" y=\"-217\" font-family=\"Helvetica,sans-Serif\" font-size=\"14.00\">function</text>\n", | |
| "</g>\n", | |
| "</g>\n", | |
| "</svg>\n" | |
| ], | |
| "text/plain": [ | |
| "<graphviz.graphs.Digraph at 0x2b6f77310>" | |
| ] | |
| }, | |
| "metadata": {}, | |
| "output_type": "display_data" | |
| } | |
| ], | |
| "source": [ | |
| "%%cell_to_module probability_estimation --display -w\n", | |
| "\n", | |
| "from scipy import stats\n", | |
| "import pandas as pd\n", | |
| "from typing import List\n", | |
| "from hamilton.function_modifiers import extract_fields\n", | |
| "\n", | |
| "def raw_data() -> str:\n", | |
| " s = \"\"\"31 weeks\t< 0.1%\t< 0.1%\t> 99.9%\n", | |
| "31 weeks, 1 day\t< 0.1%\t< 0.1%\t> 99.9%\n", | |
| "31 weeks, 2 days\t< 0.1%\t< 0.1%\t> 99.9%\n", | |
| "31 weeks, 3 days\t< 0.1%\t< 0.1%\t> 99.9%\n", | |
| "31 weeks, 4 days\t0.1%\t< 0.1%\t99.9%\n", | |
| "31 weeks, 5 days\t0.1%\t< 0.1%\t99.9%\n", | |
| "31 weeks, 6 days\t0.1%\t< 0.1%\t99.9%\n", | |
| "32 weeks\t0.1%\t< 0.1%\t99.9%\n", | |
| "32 weeks, 1 day\t0.1%\t< 0.1%\t99.9%\n", | |
| "32 weeks, 2 days\t0.1%\t< 0.1%\t99.9%\n", | |
| "32 weeks, 3 days\t0.1%\t< 0.1%\t99.8%\n", | |
| "32 weeks, 4 days\t0.2%\t< 0.1%\t99.8%\n", | |
| "32 weeks, 5 days\t0.2%\t< 0.1%\t99.8%\n", | |
| "32 weeks, 6 days\t0.2%\t< 0.1%\t99.7%\n", | |
| "33 weeks\t0.3%\t< 0.1%\t99.7%\n", | |
| "33 weeks, 1 day\t0.3%\t< 0.1%\t99.6%\n", | |
| "33 weeks, 2 days\t0.4%\t0.1%\t99.6%\n", | |
| "33 weeks, 3 days\t0.4%\t0.1%\t99.5%\n", | |
| "33 weeks, 4 days\t0.5%\t0.1%\t99.4%\n", | |
| "33 weeks, 5 days\t0.6%\t0.1%\t99.3%\n", | |
| "33 weeks, 6 days\t0.7%\t0.1%\t99.2%\n", | |
| "34 weeks\t0.8%\t0.1%\t99.1%\n", | |
| "34 weeks, 1 day\t0.9%\t0.1%\t99%\n", | |
| "34 weeks, 2 days\t1%\t0.1%\t98.9%\n", | |
| "34 weeks, 3 days\t1.2%\t0.1%\t98.7%\n", | |
| "34 weeks, 4 days\t1.3%\t0.2%\t98.5%\n", | |
| "34 weeks, 5 days\t1.5%\t0.2%\t98.3%\n", | |
| "34 weeks, 6 days\t1.7%\t0.2%\t98.1%\n", | |
| "35 weeks\t2%\t0.2%\t97.8%\n", | |
| "35 weeks, 1 day\t2.2%\t0.3%\t97.5%\n", | |
| "35 weeks, 2 days\t2.5%\t0.3%\t97.2%\n", | |
| "35 weeks, 3 days\t2.9%\t0.3%\t96.8%\n", | |
| "35 weeks, 4 days\t3.2%\t0.4%\t96.4%\n", | |
| "35 weeks, 5 days\t3.6%\t0.4%\t96%\n", | |
| "35 weeks, 6 days\t4.1%\t0.4%\t95.5%\n", | |
| "36 weeks\t4.6%\t0.5%\t95%\n", | |
| "36 weeks, 1 day\t5.1%\t0.5%\t94.4%\n", | |
| "36 weeks, 2 days\t5.7%\t0.6%\t93.7%\n", | |
| "36 weeks, 3 days\t6.3%\t0.6%\t93%\n", | |
| "36 weeks, 4 days\t7%\t0.7%\t92.2%\n", | |
| "36 weeks, 5 days\t7.8%\t0.8%\t91.4%\n", | |
| "36 weeks, 6 days\t8.7%\t0.8%\t90.5%\n", | |
| "37 weeks\t9.6%\t0.9%\t89.5%\n", | |
| "37 weeks, 1 day\t10.6%\t1%\t88.5%\n", | |
| "37 weeks, 2 days\t11.6%\t1.1%\t87.3%\n", | |
| "37 weeks, 3 days\t12.8%\t1.1%\t86.1%\n", | |
| "37 weeks, 4 days\t14%\t1.2%\t84.8%\n", | |
| "37 weeks, 5 days\t15.3%\t1.3%\t83.4%\n", | |
| "37 weeks, 6 days\t16.7%\t1.4%\t81.8%\n", | |
| "38 weeks\t18.3%\t1.5%\t80.2%\n", | |
| "38 weeks, 1 day\t19.9%\t1.6%\t78.5%\n", | |
| "38 weeks, 2 days\t21.6%\t1.7%\t76.7%\n", | |
| "38 weeks, 3 days\t23.4%\t1.8%\t74.8%\n", | |
| "38 weeks, 4 days\t25.3%\t1.9%\t72.8%\n", | |
| "38 weeks, 5 days\t27.4%\t2%\t70.6%\n", | |
| "38 weeks, 6 days\t29.5%\t2.1%\t68.4%\n", | |
| "39 weeks\t31.7%\t2.2%\t66%\n", | |
| "39 weeks, 1 day\t34.1%\t2.4%\t63.5%\n", | |
| "39 weeks, 2 days\t36.6%\t2.5%\t61%\n", | |
| "39 weeks, 3 days\t39.1%\t2.6%\t58.3%\n", | |
| "39 weeks, 4 days\t41.8%\t2.7%\t55.5%\n", | |
| "39 weeks, 5 days\t44.6%\t2.8%\t52.6%\n", | |
| "39 weeks, 6 days\t47.5%\t2.9%\t49.6%\n", | |
| "40 weeks\t50.5%\t3%\t46.5%\n", | |
| "40 weeks, 1 day\t53.6%\t3.1%\t43.4%\n", | |
| "40 weeks, 2 days\t56.7%\t3.2%\t40.1%\n", | |
| "40 weeks, 3 days\t59.9%\t3.2%\t36.8%\n", | |
| "40 weeks, 4 days\t63.2%\t3.3%\t33.5%\n", | |
| "40 weeks, 5 days\t66.5%\t3.3%\t30.2%\n", | |
| "40 weeks, 6 days\t69.8%\t3.3%\t26.9%\n", | |
| "41 weeks\t73.1%\t3.3%\t23.6%\n", | |
| "41 weeks, 1 day\t76.3%\t3.2%\t20.4%\n", | |
| "41 weeks, 2 days\t79.5%\t3.1%\t17.4%\n", | |
| "41 weeks, 3 days\t82.4%\t3%\t14.6%\n", | |
| "41 weeks, 4 days\t85.2%\t2.8%\t12%\n", | |
| "41 weeks, 5 days\t87.8%\t2.6%\t9.6%\n", | |
| "41 weeks, 6 days\t90.1%\t2.3%\t7.5%\n", | |
| "42 weeks\t92.2%\t2%\t5.8%\n", | |
| "42 weeks, 1 day\t93.9%\t1.8%\t4.3%\n", | |
| "42 weeks, 2 days\t95.4%\t1.5%\t3.1%\n", | |
| "42 weeks, 3 days\t96.6%\t1.2%\t2.2%\n", | |
| "42 weeks, 4 days\t97.6%\t0.9%\t1.5%\n", | |
| "42 weeks, 5 days\t98.3%\t0.7%\t1%\n", | |
| "42 weeks, 6 days\t98.8%\t0.5%\t0.6%\n", | |
| "43 weeks\t99.2%\t0.4%\t0.4%\n", | |
| "43 weeks, 1 day\t99.5%\t0.3%\t0.2%\n", | |
| "43 weeks, 2 days\t99.7%\t0.2%\t0.1%\n", | |
| "43 weeks, 3 days\t99.8%\t0.1%\t0.1%\n", | |
| "43 weeks, 4 days\t99.9%\t0.1%\t< 0.1%\n", | |
| "43 weeks, 5 days\t99.9%\t< 0.1%\t< 0.1%\n", | |
| "43 weeks, 6 days\t> 99.9%\t< 0.1%\"\"\".replace(\"weeks\\t\", \"weeks, 0 days \").replace(\"\\t\", \" \").split(\"\\n\")\n", | |
| " return s\n", | |
| "\n", | |
| "def raw_probabilities(raw_data: str) -> pd.DataFrame:\n", | |
| " # filter out the outliers, we'll want them back in at some point but we'll let the fitting do the job\n", | |
| " raw_data = [item for item in raw_data if \"<\" not in item and \">\" not in item] \n", | |
| " weeks = [int(item.split(',')[0].split()[0]) for item in raw_data if \"<\" not in raw_data and \">\" not in raw_data]\n", | |
| " days = [int(item.split(', ')[1].split()[0]) for item in raw_data]\n", | |
| " probability = [float(item.split()[5].replace(\"%\", \"\"))/100 for item in raw_data]\n", | |
| " probabilities_data = [(week*7+day, probability) for week, day, probability in zip(weeks, days, probability)]\n", | |
| " probabilities_df = pd.DataFrame(probabilities_data)\n", | |
| " probabilities_df.columns=[\"days\", \"probability\"]\n", | |
| " return probabilities_df#.set_index(\"days\")\n", | |
| "\n", | |
| "def resampled(raw_probabilities: pd.DataFrame) -> List[int]:\n", | |
| " sample_data = []\n", | |
| " for index, row in raw_probabilities.iterrows():\n", | |
| " count = row.probability*1000\n", | |
| " for i in range(int(count)):\n", | |
| " sample_data.append(row.days)\n", | |
| " return sample_data\n", | |
| "\n", | |
| "@extract_fields(\n", | |
| " fields={\"a\" : float, \"loc\": float, \"scale\" : float}\n", | |
| ")\n", | |
| "def distribution_params(resampled: list[int]) -> dict[str, float]:\n", | |
| " a, loc, scale = stats.skewnorm.fit(resampled)\n", | |
| " return {\n", | |
| " \"a\": a,\n", | |
| " \"loc\" : loc,\n", | |
| " \"scale\" : scale\n", | |
| " }\n", | |
| "\n", | |
| "def distribution(distribution_params: dict[str, float]) -> stats.rv_continuous:\n", | |
| " return stats.skewnorm(**distribution_params)" | |
| ] | |
| }, | |
| { | |
| "cell_type": "code", | |
| "execution_count": 36, | |
| "id": "c0adff8e", | |
| "metadata": {}, | |
| "outputs": [ | |
| { | |
| "data": { | |
| "text/plain": [ | |
| "{'a': -4.186168447183817,\n", | |
| " 'scale': 20.670154416450384,\n", | |
| " 'loc': 294.44465059093034}" | |
| ] | |
| }, | |
| "execution_count": 36, | |
| "metadata": {}, | |
| "output_type": "execute_result" | |
| } | |
| ], | |
| "source": [ | |
| "dr = driver.Builder().with_modules(probability_estimation).build()\n", | |
| "params = dr.execute([\"a\", \"scale\", \"loc\"])\n", | |
| "params" | |
| ] | |
| } | |
| ], | |
| "metadata": { | |
| "kernelspec": { | |
| "display_name": "Python 3 (ipykernel)", | |
| "language": "python", | |
| "name": "python3" | |
| }, | |
| "language_info": { | |
| "codemirror_mode": { | |
| "name": "ipython", | |
| "version": 3 | |
| }, | |
| "file_extension": ".py", | |
| "mimetype": "text/x-python", | |
| "name": "python", | |
| "nbconvert_exporter": "python", | |
| "pygments_lexer": "ipython3", | |
| "version": "3.11.9" | |
| } | |
| }, | |
| "nbformat": 4, | |
| "nbformat_minor": 5 | |
| } |