diff --git a/docs/notebooks/4a_Organise_predictions_for_a_production_pipeline.md b/docs/notebooks/4a_Organise_predictions_for_a_production_pipeline.md index 88cabae..9441dba 100644 --- a/docs/notebooks/4a_Organise_predictions_for_a_production_pipeline.md +++ b/docs/notebooks/4a_Organise_predictions_for_a_production_pipeline.md @@ -22,6 +22,9 @@ This notebook generates fake data on-the-fly, so you can run it immediately with %autoreload 2 ``` + The autoreload extension is already loaded. To reload it, use: + %reload_ext autoreload + ## Generate fake data and train simple models We reuse the fake data generation from notebooks 3a and 3c. First, fake ED snapshots for training an admission probability model: @@ -111,9 +114,10 @@ yta_model.fit( Split sizes: [2214, 710, 1584] -
ParametricIncomingAdmissionPredictor(filters={})
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
+
ParametricIncomingAdmissionPredictor(filters={})
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
We also need the aspirational curve parameters for the parametric model. These are loaded from the config file in the repository: @@ -596,11 +610,12 @@ This is exactly the kind of result we produced in the 3x\_ notebooks — a numpy ## Step 2: Wrap the PMF in a `FlowInputs` container -A `FlowInputs` object is a lightweight, immutable container that holds a single source of patient flow. It adds three pieces of metadata to the raw distribution: +A `FlowInputs` object is a lightweight, immutable container that holds a single source of patient flow. It adds metadata to the raw distribution: - **`flow_id`** — a unique identifier (e.g. `"ed_current"`) - **`flow_type`** — either `"pmf"` or `"poisson"`, so downstream code knows how to handle it - **`display_name`** — an optional human-readable label +- **`aspirational`** — whether the flow reflects demand under target performance assumptions rather than empirically observed patterns (default `False`; see notebook 4d for evaluation implications) The distribution itself is stored in the `distribution` attribute — exactly the same numpy array we just plotted. @@ -766,6 +781,8 @@ print(f'Distribution: {ed_yta_flow.distribution} (Poisson lambda)') Both PMF and Poisson flows use the same `FlowInputs` container, distinguished only by `flow_type`. This uniform interface means downstream code can handle any flow without special-casing. +Because we used a `ParametricIncomingAdmissionPredictor` here, the Poisson rate reflects demand as if ED performance targets are met — an _aspirational_ prediction. When `build_service_data()` constructs this flow automatically, it sets `aspirational=True` on the `ed_yta` `FlowInputs` so that downstream code can detect this. See notebook 4d for how this affects evaluation. + ## Step 4: Group flows into a `ServicePredictionInputs` A hospital service (e.g. "medical") has multiple sources of incoming patients and potentially outgoing patients too. `ServicePredictionInputs` groups all of these into a single object, organised as **inflows** and **outflows**. @@ -997,7 +1014,7 @@ Every call to `predictor.predict_service()` returns a `PredictionBundle`. This b - **departures** — the combined outflow distribution - **net_flow** — the difference (arrivals minus departures) -It also records which `FlowSelection` was used, so you can always trace what went into the prediction. +It also records which `FlowSelection` was used, so you can always trace what went into the prediction. The bundle's **`is_aspirational`** flag is `True` when any contributing inflow was generated under aspirational assumptions (e.g. ED performance targets), indicating that comparison against observed admissions requires care — see notebook 4d. ```python print(combined_bundle) diff --git a/notebooks/4a_Organise_predictions_for_a_production_pipeline.ipynb b/notebooks/4a_Organise_predictions_for_a_production_pipeline.ipynb index e4ce915..bfdaa15 100644 --- a/notebooks/4a_Organise_predictions_for_a_production_pipeline.ipynb +++ b/notebooks/4a_Organise_predictions_for_a_production_pipeline.ipynb @@ -1,1621 +1,1644 @@ { - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# 4a. Organise predictions for a production pipeline\n", - "\n", - "In the previous notebooks in this series, we worked with raw probability distributions — PMF arrays from group snapshots (3a, 3b) and Poisson-based distributions from yet-to-arrive models (3e). We used functions like `get_prob_dist_for_prediction_moment()` and `ParametricIncomingAdmissionPredictor.predict()` to generate these distributions, and `plot_prob_dist()` to visualise them.\n", - "\n", - "These building blocks work well for individual predictions, but a production system needs to combine multiple demand sources (current patients, yet-to-arrive patients), for multiple services (medical, surgical, paediatric, ...), at multiple times of day. How do we organise all of these predictions in a structured way?\n", - "\n", - "This notebook introduces the data classes that `patientflow` uses to organise prediction inputs and outputs for a production pipeline:\n", - "\n", - "1. **`FlowInputs`** — a named container for a single source of patient flow (a PMF array or a Poisson rate)\n", - "2. **`ServicePredictionInputs`** — a grouping of all inflows and outflows for one service\n", - "3. **`DemandPredictor`** — the prediction engine that convolves flows into a combined distribution\n", - "4. **`FlowSelection`** — a toggle for which flows to include in a prediction\n", - "5. **`PredictionBundle`** — the output: arrivals, departures, and net flow bundled together\n", - "\n", - "The 4x_ notebooks use these classes extensively. By understanding them here, you will be well prepared for the full UCLH implementation that follows.\n", - "\n", - "This notebook generates fake data on-the-fly, so you can run it immediately without any external data." - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "execution": { - "iopub.execute_input": "2026-02-23T08:42:33.672800Z", - "iopub.status.busy": "2026-02-23T08:42:33.672589Z", - "iopub.status.idle": "2026-02-23T08:42:33.782516Z", - "shell.execute_reply": "2026-02-23T08:42:33.782133Z" - } - }, - "outputs": [], - "source": [ - "# Reload functions every time\n", - "%load_ext autoreload\n", - "%autoreload 2" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Generate fake data and train simple models\n", - "\n", - "We reuse the fake data generation from notebooks 3a and 3c. First, fake ED snapshots for training an admission probability model:" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "execution": { - "iopub.execute_input": "2026-02-23T08:42:33.784126Z", - "iopub.status.busy": "2026-02-23T08:42:33.784039Z", - "iopub.status.idle": "2026-02-23T08:42:42.902811Z", - "shell.execute_reply": "2026-02-23T08:42:42.902359Z" - } - }, - "outputs": [ + "cells": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "Patient Set Overlaps (before random assignment):\n", - "Train-Valid: 0 of 5318\n", - "Valid-Test: 102 of 3690\n", - "Train-Test: 307 of 6129\n", - "All Sets: 0 of 7364 total patients\n", - "Split sizes: [6406, 2122, 4304]\n" - ] - } - ], - "source": [ - "from datetime import date, timedelta\n", - "from patientflow.generate import create_fake_snapshots, create_fake_finished_visits\n", - "from patientflow.prepare import create_temporal_splits\n", - "from patientflow.train.classifiers import train_classifier\n", - "\n", - "prediction_times = [(6, 0), (9, 30), (12, 0), (15, 30), (22, 0)]\n", - "\n", - "snapshots_df = create_fake_snapshots(\n", - " prediction_times=prediction_times,\n", - " start_date='2023-01-01',\n", - " end_date='2023-04-01',\n", - " mean_patients_per_day=100\n", - ")\n", - "\n", - "# Temporal splits\n", - "start_training_set = date(2023, 1, 1)\n", - "start_validation_set = date(2023, 2, 15)\n", - "start_test_set = date(2023, 3, 1)\n", - "end_test_set = date(2023, 4, 1)\n", - "\n", - "train_visits, valid_visits, test_visits = create_temporal_splits(\n", - " snapshots_df, start_training_set, start_validation_set,\n", - " start_test_set, end_test_set,\n", - " col_name='snapshot_date', patient_id='patient_id', visit_col='visit_number'\n", - ")\n", - "\n", - "# Train a simple admission probability model (as in notebook 3a)\n", - "model = train_classifier(\n", - " train_visits, valid_visits, test_visits=test_visits,\n", - " grid={'n_estimators': [30]},\n", - " prediction_time=(12, 0),\n", - " exclude_from_training_data=['visit_number', 'snapshot_date', 'prediction_time'],\n", - " ordinal_mappings={'latest_triage_score': [1, 2, 3, 4, 5]},\n", - " visit_col='visit_number',\n", - " use_balanced_training=True,\n", - " calibrate_probabilities=True\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Next, fake arrival data for training a yet-to-arrive model (as in notebook 3e):" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "execution": { - "iopub.execute_input": "2026-02-23T08:42:42.904874Z", - "iopub.status.busy": "2026-02-23T08:42:42.904728Z", - "iopub.status.idle": "2026-02-23T08:42:52.464102Z", - "shell.execute_reply": "2026-02-23T08:42:52.463719Z" - } - }, - "outputs": [ + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# 4a. Organise predictions for a production pipeline\n", + "\n", + "In the previous notebooks in this series, we worked with raw probability distributions — PMF arrays from group snapshots (3a, 3b) and Poisson-based distributions from yet-to-arrive models (3e). We used functions like `get_prob_dist_for_prediction_moment()` and `ParametricIncomingAdmissionPredictor.predict()` to generate these distributions, and `plot_prob_dist()` to visualise them.\n", + "\n", + "These building blocks work well for individual predictions, but a production system needs to combine multiple demand sources (current patients, yet-to-arrive patients), for multiple services (medical, surgical, paediatric, ...), at multiple times of day. How do we organise all of these predictions in a structured way?\n", + "\n", + "This notebook introduces the data classes that `patientflow` uses to organise prediction inputs and outputs for a production pipeline:\n", + "\n", + "1. **`FlowInputs`** — a named container for a single source of patient flow (a PMF array or a Poisson rate)\n", + "2. **`ServicePredictionInputs`** — a grouping of all inflows and outflows for one service\n", + "3. **`DemandPredictor`** — the prediction engine that convolves flows into a combined distribution\n", + "4. **`FlowSelection`** — a toggle for which flows to include in a prediction\n", + "5. **`PredictionBundle`** — the output: arrivals, departures, and net flow bundled together\n", + "\n", + "The 4x_ notebooks use these classes extensively. By understanding them here, you will be well prepared for the full UCLH implementation that follows.\n", + "\n", + "This notebook generates fake data on-the-fly, so you can run it immediately without any external data." + ] + }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "Split sizes: [2214, 710, 1584]\n" - ] + "cell_type": "code", + "execution_count": 25, + "metadata": { + "execution": { + "iopub.execute_input": "2026-02-23T08:42:33.672800Z", + "iopub.status.busy": "2026-02-23T08:42:33.672589Z", + "iopub.status.idle": "2026-02-23T08:42:33.782516Z", + "shell.execute_reply": "2026-02-23T08:42:33.782133Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "The autoreload extension is already loaded. To reload it, use:\n", + " %reload_ext autoreload\n" + ] + } + ], + "source": [ + "# Reload functions every time\n", + "%load_ext autoreload\n", + "%autoreload 2" + ] }, { - "data": { - "text/html": [ - "
ParametricIncomingAdmissionPredictor(filters={})
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
" + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Generate fake data and train simple models\n", + "\n", + "We reuse the fake data generation from notebooks 3a and 3c. First, fake ED snapshots for training an admission probability model:" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": { + "execution": { + "iopub.execute_input": "2026-02-23T08:42:33.784126Z", + "iopub.status.busy": "2026-02-23T08:42:33.784039Z", + "iopub.status.idle": "2026-02-23T08:42:42.902811Z", + "shell.execute_reply": "2026-02-23T08:42:42.902359Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "Patient Set Overlaps (before random assignment):\n", + "Train-Valid: 0 of 5318\n", + "Valid-Test: 102 of 3690\n", + "Train-Test: 307 of 6129\n", + "All Sets: 0 of 7364 total patients\n", + "Split sizes: [6406, 2122, 4304]\n" + ] + } ], - "text/plain": [ - "ParametricIncomingAdmissionPredictor(filters={})" + "source": [ + "from datetime import date, timedelta\n", + "from patientflow.generate import create_fake_snapshots, create_fake_finished_visits\n", + "from patientflow.prepare import create_temporal_splits\n", + "from patientflow.train.classifiers import train_classifier\n", + "\n", + "prediction_times = [(6, 0), (9, 30), (12, 0), (15, 30), (22, 0)]\n", + "\n", + "snapshots_df = create_fake_snapshots(\n", + " prediction_times=prediction_times,\n", + " start_date='2023-01-01',\n", + " end_date='2023-04-01',\n", + " mean_patients_per_day=100\n", + ")\n", + "\n", + "# Temporal splits\n", + "start_training_set = date(2023, 1, 1)\n", + "start_validation_set = date(2023, 2, 15)\n", + "start_test_set = date(2023, 3, 1)\n", + "end_test_set = date(2023, 4, 1)\n", + "\n", + "train_visits, valid_visits, test_visits = create_temporal_splits(\n", + " snapshots_df, start_training_set, start_validation_set,\n", + " start_test_set, end_test_set,\n", + " col_name='snapshot_date', patient_id='patient_id', visit_col='visit_number'\n", + ")\n", + "\n", + "# Train a simple admission probability model (as in notebook 3a)\n", + "model = train_classifier(\n", + " train_visits, valid_visits, test_visits=test_visits,\n", + " grid={'n_estimators': [30]},\n", + " prediction_time=(12, 0),\n", + " exclude_from_training_data=['visit_number', 'snapshot_date', 'prediction_time'],\n", + " ordinal_mappings={'latest_triage_score': [1, 2, 3, 4, 5]},\n", + " visit_col='visit_number',\n", + " use_balanced_training=True,\n", + " calibrate_probabilities=True\n", + ")" ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "import pandas as pd\n", - "from patientflow.predictors.incoming_admission_predictors import ParametricIncomingAdmissionPredictor\n", - "\n", - "visits_df, _, _ = create_fake_finished_visits(\n", - " '2023-01-01', '2023-04-01', mean_patients_per_day=50, admitted_only=True\n", - ")\n", - "inpatient_arrivals = visits_df.rename(\n", - " columns={'departure_datetime': 'admitted_to_ward_datetime'}\n", - ").drop(columns='is_admitted')\n", - "inpatient_arrivals['arrival_datetime'] = pd.to_datetime(inpatient_arrivals['arrival_datetime'])\n", - "\n", - "train_arrivals, _, _ = create_temporal_splits(\n", - " inpatient_arrivals, start_training_set, start_validation_set,\n", - " start_test_set, end_test_set, col_name='arrival_datetime'\n", - ")\n", - "\n", - "# Train a parametric yet-to-arrive model (as in notebook 3e)\n", - "train_arrivals_copy = train_arrivals.copy(deep=True)\n", - "if 'arrival_datetime' in train_arrivals_copy.columns:\n", - " train_arrivals_copy.set_index('arrival_datetime', inplace=True)\n", - "\n", - "num_days = (start_validation_set - start_training_set).days\n", - "\n", - "yta_model = ParametricIncomingAdmissionPredictor(verbose=False)\n", - "yta_model.fit(\n", - " train_arrivals_copy,\n", - " prediction_window=timedelta(hours=8),\n", - " yta_time_interval=timedelta(minutes=15),\n", - " prediction_times=prediction_times,\n", - " num_days=num_days\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We also need the aspirational curve parameters for the parametric model. These are loaded from the config file in the repository:" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "execution": { - "iopub.execute_input": "2026-02-23T08:42:52.465430Z", - "iopub.status.busy": "2026-02-23T08:42:52.465338Z", - "iopub.status.idle": "2026-02-23T08:42:52.490021Z", - "shell.execute_reply": "2026-02-23T08:42:52.489638Z" - } - }, - "outputs": [ + }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "Inferred project root: /Users/zellaking/Repos/patientflow\n", - "Aspirational targets: 80% admitted within 4 hours, 99% within 12 hours\n" - ] - } - ], - "source": [ - "from patientflow.load import load_config_file, set_file_paths, set_project_root\n", - "\n", - "project_root = set_project_root()\n", - "_, _, _, config_path = set_file_paths(project_root, data_folder_name='data-public', verbose=False)\n", - "params = load_config_file(config_path)\n", - "x1, y1, x2, y2 = params['x1'], params['y1'], params['x2'], params['y2']\n", - "\n", - "print(f'Aspirational targets: {y1*100:.0f}% admitted within {x1:.0f} hours, '\n", - " f'{y2*100:.0f}% within {x2:.0f} hours')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Step 1: Start with a familiar result — a raw PMF array\n", - "\n", - "In notebook 3a we used `get_prob_dist_for_prediction_moment()` to predict a bed count distribution for a group of patients. The result was a raw PMF array — an array where each element gives the probability of needing that many beds.\n", - "\n", - "Let's reproduce this here, selecting one group snapshot from the fake data and passing it through the trained model." - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "execution": { - "iopub.execute_input": "2026-02-23T08:42:52.491518Z", - "iopub.status.busy": "2026-02-23T08:42:52.491429Z", - "iopub.status.idle": "2026-02-23T08:42:52.514854Z", - "shell.execute_reply": "2026-02-23T08:42:52.514400Z" - } - }, - "outputs": [ + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, fake arrival data for training a yet-to-arrive model (as in notebook 3e):" + ] + }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "Snapshot: 21 patients in the ED at 12:00 on 2023-01-01\n", - "PMF array shape: (22,)\n", - "Sum of probabilities: 1.0000\n" - ] - } - ], - "source": [ - "from patientflow.prepare import prepare_patient_snapshots, prepare_group_snapshot_dict\n", - "from patientflow.aggregate import get_prob_dist_for_prediction_moment\n", - "\n", - "# Select a single group snapshot — all patients at 12:00 on a particular date\n", - "prediction_time = (12, 0)\n", - "group_snapshots_dict = prepare_group_snapshot_dict(\n", - " snapshots_df[snapshots_df.prediction_time == prediction_time]\n", - ")\n", - "snapshot_date = list(group_snapshots_dict.keys())[0]\n", - "snapshot_ids = group_snapshots_dict[snapshot_date]\n", - "\n", - "# Prepare for the model\n", - "X_test, y_test = prepare_patient_snapshots(\n", - " df=snapshots_df.loc[snapshot_ids],\n", - " prediction_time=prediction_time,\n", - " single_snapshot_per_visit=False,\n", - " label_col='is_admitted'\n", - ")\n", - "\n", - "# Generate the probability distribution — the same approach as in notebook 3a\n", - "bed_count_prob_dist = get_prob_dist_for_prediction_moment(\n", - " X_test, model, inference_time=True\n", - ")\n", - "\n", - "# The result is a raw PMF: probabilities indexed by bed count\n", - "pmf_array = bed_count_prob_dist['agg_predicted']['agg_proba'].values\n", - "print(f'Snapshot: {len(snapshot_ids)} patients in the ED at 12:00 on {snapshot_date}')\n", - "print(f'PMF array shape: {pmf_array.shape}')\n", - "print(f'Sum of probabilities: {pmf_array.sum():.4f}')" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "execution": { - "iopub.execute_input": "2026-02-23T08:42:52.516252Z", - "iopub.status.busy": "2026-02-23T08:42:52.516137Z", - "iopub.status.idle": "2026-02-23T08:42:52.977283Z", - "shell.execute_reply": "2026-02-23T08:42:52.976808Z" - } - }, - "outputs": [ + "cell_type": "code", + "execution_count": 27, + "metadata": { + "execution": { + "iopub.execute_input": "2026-02-23T08:42:42.904874Z", + "iopub.status.busy": "2026-02-23T08:42:42.904728Z", + "iopub.status.idle": "2026-02-23T08:42:52.464102Z", + "shell.execute_reply": "2026-02-23T08:42:52.463719Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Split sizes: [2214, 710, 1584]\n" + ] + }, + { + "data": { + "text/html": [ + "
ParametricIncomingAdmissionPredictor(filters={})
In a Jupyter environment, please rerun this cell to show the HTML representation or trust the notebook.
On GitHub, the HTML representation is unable to render, please try loading this page with nbviewer.org.
" + ], + "text/plain": [ + "ParametricIncomingAdmissionPredictor(filters={})" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import pandas as pd\n", + "from patientflow.predictors.incoming_admission_predictors import ParametricIncomingAdmissionPredictor\n", + "\n", + "visits_df, _, _ = create_fake_finished_visits(\n", + " '2023-01-01', '2023-04-01', mean_patients_per_day=50, admitted_only=True\n", + ")\n", + "inpatient_arrivals = visits_df.rename(\n", + " columns={'departure_datetime': 'admitted_to_ward_datetime'}\n", + ").drop(columns='is_admitted')\n", + "inpatient_arrivals['arrival_datetime'] = pd.to_datetime(inpatient_arrivals['arrival_datetime'])\n", + "\n", + "train_arrivals, _, _ = create_temporal_splits(\n", + " inpatient_arrivals, start_training_set, start_validation_set,\n", + " start_test_set, end_test_set, col_name='arrival_datetime'\n", + ")\n", + "\n", + "# Train a parametric yet-to-arrive model (as in notebook 3e)\n", + "train_arrivals_copy = train_arrivals.copy(deep=True)\n", + "if 'arrival_datetime' in train_arrivals_copy.columns:\n", + " train_arrivals_copy.set_index('arrival_datetime', inplace=True)\n", + "\n", + "num_days = (start_validation_set - start_training_set).days\n", + "\n", + "yta_model = ParametricIncomingAdmissionPredictor(verbose=False)\n", + "yta_model.fit(\n", + " train_arrivals_copy,\n", + " prediction_window=timedelta(hours=8),\n", + " yta_time_interval=timedelta(minutes=15),\n", + " prediction_times=prediction_times,\n", + " num_days=num_days\n", + ")" + ] + }, { - "data": { - "image/png": "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esm1a9e09Sl07txZizTtjRx27dqlL/z9xx9/6N/2XLVBgwbJ+vXr5ejRo7Jx40Zp3bq15vB16NAh3ukkIiIicnXwhqCpb9++8tlnn2mLTtQtQ50yBFRx0a5dO5k0aZIMHz5cKleurIEYGhqYRgxoJYp+2oyTJ09KlSpV9IXp+C7+fuGFFzzznDhxQgO1UqVKyXPPPSf33XefbN68WfLkyROfTSUiIiIKKxGWZVkJWQA61507d64sWrRI33fs2FF69OihHe66FboKQatTNF7Ili1bqJNDycxjbfskeBmrls505TKJiMLRFZc99xPc2rRq1apatImcONQvQwe7qMuG7jkwnBURERERhUHwdvv2bS02ffzxx6Vo0aLyzTffyIwZM7S1KOqgYRq67CAiIiKiEHcV0q9fPy0mRYnr888/LxMmTJDy5ct7Ps+cObPWR8MoB0REREQU4uDt119/lXfeeUeeeeYZv/2joR+3xOhShIiIiIgSWGwaGRmpRaK+gdudO3dkw4YNnsHhGzZsGJ/FExEREVFiBm+PPvqoXLx4Mdp0tNLAZ0REREQURsWmqOsWERERbfqFCxe0vhtRcsHuMoiIyNXBG+q4AQK3rl27ehWb3r17V3bv3i1169ZN/FQSERERUdyDN3RgZ3LesmbNKhkzZvQaq7R27drSs2fPuCySiIiIiIIVvGEkBShWrJiOIcoiUiIiIiIX1HlDa1MiIiIiCuPgDcNgrV69WnLmzKmDwTs1WLCPd0pEREREIQzeWrZs6Wmg0KpVqyAkhYiIiIgSLXizF5Wy2JSIiIjIZQPTExEREVEY57yhrltM9dzsnEZfICIiIqIkDN6mTp2aCKsjIiIioiQJ3rp06ZKgFRERERFREgZvV65ckWzZsnn+jomZj4iIiIhCWOft1KlTkjdvXsmRI4dj/TczYD3GOSUiIiKiEAZva9askVy5cunfa9euDUJSiIiIiCjRgreGDRs6/k1EREREYT62Kfz555/ywQcfyL59+/R92bJlpVu3bp7cOSIiIiIKk056N2zYIMWKFZPp06drEIcX/i5evLh+RkRERERhlPPWp08fadeuncyaNUtSp06t09BIoXfv3vrZL7/8ktjpJCIiIqL45rwdOnRIBg4c6AncAH8PGDBAPyMiIiKiMAreqlat6qnrZodplSpVSox0EREREVFCik13797t+fvll1+W/v37ay5b7dq1ddrmzZtl5syZMm7cuEAXSURERETBCt4qV66sHfCiI15jyJAh0ebr2LGj1ocjInLyWNs+CV7GqqUzEyUtRETJOng7cuRIcFNCRERERIkXvBUtWjTQWYmIiIgo3DrphV9//VWOHTsmUVFRXtOffvrphKaLiIiIiBKrten//vc/bVVavnx5eeKJJ6RVq1b6at26tb7iAo0c0OFvhgwZpFatWrJ161a/8+7du1fatGmj86P+3dSpUxO8TCIiIqJkH7yhpSlGUzh79qxkypRJgyqMrFC9enVZt25dwMtZsmSJ9g0XGRkpO3bs0ICwWbNmulwn169flwceeEBbtObPnz9RlklERESU7IO3TZs2yahRoyR37tySKlUqfdWvX1/Gjh2r3YgEasqUKdKzZ08dExVjo86ePVuDwQ8//NBx/ho1asjEiROlffv2kj59+kRZJhEREVGyD94wFFbWrFn1bwRwJ0+e9DRqOHDgQEDLQD257du3S5MmTf4vMalS6XsEh/ER32XeunVLrly54vUiIiIiSjbBG+q6/fzzz/o36pRNmDBBfvzxR82NQ7FmIM6fP69BYL58+bym4/3p06fjk6x4LxM5htmzZ/e8ihQpEq/1ExEREYVl8Pbmm2/KvXv39G8EbOgDrkGDBvL111/L9OnTxW2GDh0qly9f9ryOHz8e6iQRERERJV5XIWgAYJQoUUL2798vFy9elJw5c2or0ECguBWD2Z85c8ZrOt77a4wQrGWi/py/OnRERERErs95s0MuFV65cuUKOHCDdOnSSbVq1WT16tWeacjNw/s6derEKy3BWCYRERGR64O3O3fuyLBhw7R+GPpTwwt/ozj19u3bAS8HXXrMmTNH5s+fL/v27ZNevXrJtWvXtKUodO7cWYs07Q0Sdu3apS/8/ccff+jfhw4dCniZRERERCmu2LRfv37yxRdfaEMFk6OF1pwjRoyQCxcuyKxZswJaDgawP3funAwfPlwbFFSuXFlWrlzpaXCA0RvQWtRAq9YqVap43k+aNElfDRs29PQvF9syiYiIiFJc8LZw4UJZvHixtGjRwjOtYsWK2kqzQ4cOAQdv0LdvX3058e3wFzl8lmUlaJlEREREKa7YFJX7EUj5wqgLqHdGRERERGEUvCFXa/To0dq5rYG/33rrLeZ4EREREYVDsekzzzzj9f67776TwoUL69ihgE570YigcePGiZ9KIiIiIopb8IbWpHZt2rTxes9RCYiIiIjCKHibO3ducFNCRERERMFpbWqgSw4zEH2pUqUkT548CVkcEREREQWjwQI6ve3evbsUKFBAHn74YX0VLFhQevToIdevX4/PIomIiIgoWMEbRjFYv369fPXVV3Lp0iV9ffnllzpt4MCB8VkkEREREQWr2PTzzz+Xzz77TB555BHPtMcff1wyZswozz33XJw66SUiIiKiIOe8oWjUabipvHnzstiUiIiIKNyCN4xnGhkZKTdv3vRMu3HjhowcOdIz1ikRERERhUmx6dSpU6V58+bROunNkCGDfPPNN4mdRiIiIiJKSPBWoUIFOXjwoHzyySeyf/9+nYYB6Tt16qT13oiIiIgoTIK327dvS+nSpWXFihXSs2fP4KSKiIiIiBKnzlvatGm96roRERERUZg3WOjTp4+MHz9e7ty5k/gpIiIiIqLErfP2008/yerVq+Xbb7/V+m+ZM2f2+vyLL76Iz2KJiIiIKBjBW44cOaRNmzbx+SoRERERJVXwdu/ePZk4caL89ttvEhUVJY0aNZIRI0awhSmF3GNt+yR4GauWzkyUtBAREYVNnbe33npL3njjDcmSJYsUKlRIpk+frvXfiIiIiCgMg7cFCxbIu+++qx3xLl++XAemR19vyJEjIiIiojAL3o4dO6YD0BtNmjSRiIgIOXnyZDDSRkREREQJCd7QNQiGwPLt9w0d9xIRERFRmDVYsCxLunbtKunTp/dMQ4e9L730kld3IewqhIiIiCgMgrcuXbpEm/a3v/0tMdNDRERERIkVvM2dOzcusxMRERFROAyPRUREREShweCNiIiIyEUYvBERERG5CIM3IiIiIhdh8EZERESUXFubBsvMmTN1wPvTp09LpUqV5J133pGaNWv6nX/p0qUybNgwOXr0qJQsWVLGjx/vNfID+qKbP3++13eaNWsmK1euDOp2EFFoPNY24WMsr1o6M1HSQkSU7HPelixZIgMGDJDIyEjZsWOHBm8ItM6ePes4/8aNG6VDhw7So0cP2blzp7Rq1Upfe/bs8ZqvefPmcurUKc9r0aJFSbRFRERERMk4eJsyZYr07NlTunXrJmXLlpXZs2dLpkyZ5MMPP3Scf9q0aRqYDR48WMqUKSOjR4+WqlWryowZM7zmwygQ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", - "text/plain": [ - "
" + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We also need the aspirational curve parameters for the parametric model. These are loaded from the config file in the repository:" ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "import numpy as np\n", - "from patientflow.viz.probability_distribution import plot_prob_dist\n", - "from patientflow.viz.utils import format_prediction_time\n", - "\n", - "title = (\n", - " f'Probability distribution for number of beds needed by the '\n", - " f'{len(snapshot_ids)} patients\\n'\n", - " f'in the ED at {format_prediction_time(prediction_time)} '\n", - " f'on {snapshot_date}'\n", - ")\n", - "plot_prob_dist(pmf_array, title, include_titles=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This is exactly the kind of result we produced in the 3x_ notebooks — a numpy array of probabilities. Now let's see how `patientflow` wraps this in a named container." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Step 2: Wrap the PMF in a `FlowInputs` container\n", - "\n", - "A `FlowInputs` object is a lightweight, immutable container that holds a single source of patient flow. It adds three pieces of metadata to the raw distribution:\n", - "\n", - "- **`flow_id`** — a unique identifier (e.g. `\"ed_current\"`)\n", - "- **`flow_type`** — either `\"pmf\"` or `\"poisson\"`, so downstream code knows how to handle it\n", - "- **`display_name`** — an optional human-readable label\n", - "\n", - "The distribution itself is stored in the `distribution` attribute — exactly the same numpy array we just plotted." - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": { - "execution": { - "iopub.execute_input": "2026-02-23T08:42:52.978607Z", - "iopub.status.busy": "2026-02-23T08:42:52.978477Z", - "iopub.status.idle": "2026-02-23T08:42:53.015054Z", - "shell.execute_reply": "2026-02-23T08:42:53.014672Z" - } - }, - "outputs": [ + }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "Flow ID: ed_current\n", - "Flow type: pmf\n", - "Display name: Admissions from current ED\n", - "Distribution: numpy array of shape (22,)\n", - "Same data? True\n" - ] - } - ], - "source": [ - "from patientflow.predict.service import FlowInputs\n", - "\n", - "ed_current_flow = FlowInputs(\n", - " flow_id=\"ed_current\",\n", - " flow_type=\"pmf\",\n", - " distribution=pmf_array,\n", - " display_name=\"Admissions from current ED\"\n", - ")\n", - "\n", - "print(f'Flow ID: {ed_current_flow.flow_id}')\n", - "print(f'Flow type: {ed_current_flow.flow_type}')\n", - "print(f'Display name: {ed_current_flow.get_display_name()}')\n", - "print(f'Distribution: numpy array of shape {ed_current_flow.distribution.shape}')\n", - "print(f'Same data? {np.array_equal(ed_current_flow.distribution, pmf_array)}')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The data inside `FlowInputs` is exactly the same PMF array. The container simply gives it a name and a type." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Step 3: Wrap a Poisson rate in a `FlowInputs` container\n", - "\n", - "In notebook 3e, we used Poisson distributions to model yet-to-arrive patients. The yet-to-arrive model's `predict()` method returns a full probability distribution — a DataFrame with an `agg_proba` column, just like the bed count distributions from notebook 3a.\n", - "\n", - "Let's call `predict()` on the model we just trained to see the result." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": { - "execution": { - "iopub.execute_input": "2026-02-23T08:42:53.016460Z", - "iopub.status.busy": "2026-02-23T08:42:53.016355Z", - "iopub.status.idle": "2026-02-23T08:42:53.035498Z", - "shell.execute_reply": "2026-02-23T08:42:53.035054Z" - } - }, - "outputs": [ + "cell_type": "code", + "execution_count": 28, + "metadata": { + "execution": { + "iopub.execute_input": "2026-02-23T08:42:52.465430Z", + "iopub.status.busy": "2026-02-23T08:42:52.465338Z", + "iopub.status.idle": "2026-02-23T08:42:52.490021Z", + "shell.execute_reply": "2026-02-23T08:42:52.489638Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Inferred project root: /Users/zellaking/Repos/patientflow\n", + "Aspirational targets: 80% admitted within 4 hours, 99% within 12 hours\n" + ] + } + ], + "source": [ + "from patientflow.load import load_config_file, set_file_paths, set_project_root\n", + "\n", + "project_root = set_project_root()\n", + "_, _, _, config_path = set_file_paths(project_root, data_folder_name='data-public', verbose=False)\n", + "params = load_config_file(config_path)\n", + "x1, y1, x2, y2 = params['x1'], params['y1'], params['x2'], params['y2']\n", + "\n", + "print(f'Aspirational targets: {y1*100:.0f}% admitted within {x1:.0f} hours, '\n", + " f'{y2*100:.0f}% within {x2:.0f} hours')" + ] + }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "Yet-to-arrive distribution (first 10 rows):\n" - ] + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Step 1: Start with a familiar result — a raw PMF array\n", + "\n", + "In notebook 3a we used `get_prob_dist_for_prediction_moment()` to predict a bed count distribution for a group of patients. The result was a raw PMF array — an array where each element gives the probability of needing that many beds.\n", + "\n", + "Let's reproduce this here, selecting one group snapshot from the fake data and passing it through the trained model." + ] }, { - "data": { - "text/html": [ - "
\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", - "
agg_proba
sum
08.208667e-09
11.528296e-07
21.422696e-06
38.829289e-06
44.109609e-05
51.530260e-04
64.748417e-04
71.262948e-03
82.939208e-03
96.080267e-03
\n", - "
" + "cell_type": "code", + "execution_count": 29, + "metadata": { + "execution": { + "iopub.execute_input": "2026-02-23T08:42:52.491518Z", + "iopub.status.busy": "2026-02-23T08:42:52.491429Z", + "iopub.status.idle": "2026-02-23T08:42:52.514854Z", + "shell.execute_reply": "2026-02-23T08:42:52.514400Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Snapshot: 21 patients in the ED at 12:00 on 2023-01-01\n", + "PMF array shape: (22,)\n", + "Sum of probabilities: 1.0000\n" + ] + } ], - "text/plain": [ - " agg_proba\n", - "sum \n", - "0 8.208667e-09\n", - "1 1.528296e-07\n", - "2 1.422696e-06\n", - "3 8.829289e-06\n", - "4 4.109609e-05\n", - "5 1.530260e-04\n", - "6 4.748417e-04\n", - "7 1.262948e-03\n", - "8 2.939208e-03\n", - "9 6.080267e-03" + "source": [ + "from patientflow.prepare import prepare_patient_snapshots, prepare_group_snapshot_dict\n", + "from patientflow.aggregate import get_prob_dist_for_prediction_moment\n", + "\n", + "# Select a single group snapshot — all patients at 12:00 on a particular date\n", + "prediction_time = (12, 0)\n", + "group_snapshots_dict = prepare_group_snapshot_dict(\n", + " snapshots_df[snapshots_df.prediction_time == prediction_time]\n", + ")\n", + "snapshot_date = list(group_snapshots_dict.keys())[0]\n", + "snapshot_ids = group_snapshots_dict[snapshot_date]\n", + "\n", + "# Prepare for the model\n", + "X_test, y_test = prepare_patient_snapshots(\n", + " df=snapshots_df.loc[snapshot_ids],\n", + " prediction_time=prediction_time,\n", + " single_snapshot_per_visit=False,\n", + " label_col='is_admitted'\n", + ")\n", + "\n", + "# Generate the probability distribution — the same approach as in notebook 3a\n", + "bed_count_prob_dist = get_prob_dist_for_prediction_moment(\n", + " X_test, model, inference_time=True\n", + ")\n", + "\n", + "# The result is a raw PMF: probabilities indexed by bed count\n", + "pmf_array = bed_count_prob_dist['agg_predicted']['agg_proba'].values\n", + "print(f'Snapshot: {len(snapshot_ids)} patients in the ED at 12:00 on {snapshot_date}')\n", + "print(f'PMF array shape: {pmf_array.shape}')\n", + "print(f'Sum of probabilities: {pmf_array.sum():.4f}')" ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "prediction_context = {'unfiltered': {'prediction_time': prediction_time}}\n", - "\n", - "# predict() returns a full probability distribution\n", - "yta_prediction = yta_model.predict(prediction_context, x1=x1, y1=y1, x2=x2, y2=y2, max_value=50)\n", - "yta_distribution = yta_prediction['unfiltered']\n", - "\n", - "print('Yet-to-arrive distribution (first 10 rows):')\n", - "yta_distribution.head(10)" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": { - "execution": { - "iopub.execute_input": "2026-02-23T08:42:53.036791Z", - "iopub.status.busy": "2026-02-23T08:42:53.036699Z", - "iopub.status.idle": "2026-02-23T08:42:53.104101Z", - "shell.execute_reply": "2026-02-23T08:42:53.103630Z" - } - }, - "outputs": [ + }, { - "data": { - "image/png": "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wcPBoEkjQ8MSyX0aJ8DTAW7bts126A46rC1btthTxB0ITnRynTt3tnnLSehjx441q1atsvmUnuBB40bI5be8h0GMZSz+X7p0qe0seD4dBfHl+QwKdH5o1e655x47oHPCur9TpJwZWBj0+T1CAnVnwIABZuvWrVZwija/Eg15GnqSO2WI8Dpo0KDAAMTJ72jJGPD9MPOkvMlfB3+ff/75QUIXMLi45UIEpEhMnz7d5hnOZWkbxIcT4X/99Vf7nR8GTuodkxqEUJYsGWAZpPk9UK9atmxp60v37t2tNm7GjBm2fcYC5YvQT74wgFJuGCpPmzYtEAb7OZ5LnBCWSQeOchk8yBdn00adom1Sl/r3728HPQRShMI333wz0AdQPpQFee/CUSejHVijqdMZMXToUBsO4QStLOlGk0k5unjMnz/fTi7p58gf+h7qMUIgfZEre+oRGkwGeuoW6SJ8qAARqe+j36Uc3UYf18/xv4N8xo4vkkkDE9LvvvvOTJkyxdo8uvpPnBy8A01Qjx49rGCGIHfzzTebjRs32jqZHtGMAeGgziIsU3+rVKliT6igf0Obi9Dn7+firafk/eDBg2050k5Y8qeesrEmo34yPThZgz6BCQ1CHX/zLuzAMAugHjB+YKu5cuVK87e//c1kKzEdiyxihlPdOcXbcdNNN9krT5483vvvv2/vrVy50p5g/fbbbwfCcYo29zip3LFjxw57cvf9998fuHfffffZcJ988knQaducdl6pUiXv2LFjEePGSfb8dvbs2fbz6tWr7WdO/a5fv34gHCfDc8J86Ank/hPnw53kHs1p6JzkfejQoaB7v/32m1eqVCl72rzDnQ5epEgRmw9+eAfftW/fPs3z3XcOTobn83PPPRcUrkePHt5pp53mHThwwH4mPwn32muvBYWbM2dO2PuhuOf4mTJlSpoyjXSaOyfQh55O705d58T57777Luh+//79bZ3auHFjhvkVbb0NLc/0IE2cxD5w4MCg+y59/npAWkPzwUHdK126dFA+XH311WnCrV271j5j/PjxMZfDsGHDbFx/+eWXoPrL8x5//PGgsNT7OnXqBD7PnDnThhsxYkRQHW7UqJG9P2nSpHTjw/eEa9q0qXf8+PHA/T59+tjy+/333wNtuFixYl63bt2Cfr9t2zavaNGiQfebNGni1ahRwzt48GDgHs9u2LCh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5rvvvrMe2YUQQgghsk0zxdKZ096kZ8wdCyytderUydStW9fUq1fPjB492uzfv9/u7oOOHTuasmXLWpsm6N27t12qGzlypGnRooWZOnWqWb58uZkwYULgmez0a9eunbniiiusm4Y5c+aYd99917pJEEIIIYTINmHKv7SXiGU+QOjZuXOnefTRR60ROfZNCD/OyBxHm+zwc7BTcPLkyeaRRx4xDz/8sKlcubLdyec/ygaDc+yjEMDuvfdeU6VKFfPmm29a31NCCCGEECeFzVQi6dWrl73CEU6bhOf1jA5Q7tKli72EEEIIIU4aYer0008P66gzHOG8owshsh8dviuEENkoTGHPJIQQQgghMilMYSguhBBCCCEyKUzhyLJIkSKBv9PDhRNCCCGESHVispnaunWrPTC4WLFiYe2n3AHIHBMjhBBCCJETiFqYmj9/vilevLj9e8GCBVkZJyGEEEKI1BOm/OfaRTrjTgghhBAip5FpP1McLfPSSy+Zb7/91n7mPDw8lzvtlRBCCCFETiDqs/n8fPzxx6ZSpUrm2WeftUIVF3+fffbZ9jshhBBCiJxCpjRTPXv2tEfBvPDCCyZPnjz2HkbnPXr0sN99/fXXiY6nEEIIIUTqCFM//PCDeeONNwKCFPA3Bxe/8soriYyfEELkCOSdXogctsxXu3btgK2UH+7VrFkzEfESQgghhEgtzdTq1asDf997772md+/eVkN16aWX2ntLly4148aNM8OHD8+amAohhBBCJLMwVatWLeuQE8ecjgcffDBNuNtuu83aUwkhhBBC5ASiFqY2bNiQtTERQgghhEhlYapixYpZGxMhhBBCiJzktBO++eYbs3HjRnP48OGg+zfeeGO88RJCCCGESF1h6qeffjKtW7e2/qT8dlTu8GMddCyEEEKInEKmXCOwkw9v5zt27DAFCxY0a9eutZ7P69ataxYuXJj4WAohhBBCpJJmasmSJWb+/PmmRIkSJnfu3Pa6/PLLzbBhw6zbhFWrViU+pkIIIYQQqaKZYhmvcOHC9m8Eqi1btgSM1NevX5/YGAohhBBCpJpmqnr16uarr76yS33169c3I0aMMPny5TMTJkww55xzTuJjKYQQQgiRSsLUI488Yvbv32//fvzxx831119vGjVqZM444wwzbdq0RMdRCCGEECK1hKnmzZsH/j7vvPPMunXrzJ49e8zpp58e2NEnhBBCCJETiMvPFGzatMn+X758+UTERwghhBAi9Q3Qjx49agYOHGiKFi1qKlWqZC/+ZvnvyJEjiY+lEEIIIUQqaabuuece89Zbb1nD8wYNGgTcJTz22GNm9+7d5oUXXkh0PIUQEcg1OOOldW/Q/x1QLoQQ4iTQTE2ePNm8/PLL5q677jIXXXSRvfj7pZdest/Fyrhx46x2q0CBAnZ34LJly9INP336dFO1alUbvkaNGmb27NkRw3bv3t3acY0ePTrmeAkhhBBCZIkwlT9/fiv8hIKrBFwkxAK7//r27WsGDRpkVq5caWrWrGkN3PGuHo7Fixeb9u3bm65du1rnoK1atbLXmjVr0oSdMWOGWbp0qSlTpkxMcRJCCCGEyFJhqlevXmbIkCHm0KFDgXv8PXToUPtdLIwaNcp069bNdO7c2VxwwQVm/Pjx9oiaiRMnhg0/ZswYc80115h+/fqZatWq2XjUrl3bjB07Nijc5s2b7XLka6+9Zk455ZTMJFMIIYQQInE2UzfddFPQ548++siUK1fOapIAJ56HDx82TZo0ifaRNvyKFSvMgAEDAvc4mqZp06bWBisc3EeT5QdN1syZMwOfjx8/bm6//XYrcF144YUZxgNB0C8Y7tu3L+o0CCGEECJnE7UwxW49PzfffHPQ58y4Rti1a5c9mqZUqVJB9/mM76pwbNu2LWx47jueeuopkzdvXntOYDRwpuDgwYNjjr8QQgghRNTC1KRJk0wygKaLpUDsr6J1IIpmzK/tQjMlv1lCiJMV7eAUIoWcdu7cuTNwsHGVKlXMmWeeGdPvOSQ5T548Zvv27UH3+Vy6dOmwv+F+euE/+eQTa7xeoUKFwPdov+6//367o+/nn38Oa1DPJYQQQghxQgzQOZevS5cu5qyzzjJXXHGFvdgxxw67AwcORP0cdv7VqVPHzJs3L8jeic/Of1Uo3PeHh7lz5wbCYyu1evVq8+WXXwYu4ob91AcffJCZ5AohhBBCJFYzxZLYokWLzLvvvmsuu+wye+/TTz+1NkpogGJx2smzOnXqZOrWrWvq1atntUcIa+zug44dO5qyZctauybo3bu3ady4sRk5cqRp0aKFmTp1qlm+fLmZMGGC/Z7Dlrn8sJsPzRXaMyGEEEKIbBem3nzzTfPGG2+YK6+8MnDvuuuuM6eeeqpp27ZtTMJUu3bt7HLho48+ao3Ia9WqZebMmRMwMt+4caPd4edo2LChdQzK0TUPP/ywqVy5st3JV7169cwkRQghhBDixAtTLOWF7qiDkiVLxrTM58A3VST/VAsXLkxzr02bNvaKlnB2UkIIIYQQ2WYzhX0SHssPHjwYuPfXX39Z9wKRbJ2EEEIIIVKRTGmmsGvCC3mo007OypORtxBCCCFyEpkSpjhc+Pvvv7dHtTjnmpyX16FDB2s3JYQQQgiRU4hZmDpy5IipWrWqmTVrlj1TTwghhBAiJxOzzRRuBvy2UkIIIYQQOZlMGaD37NnTnn939OjRxMdICCGEECLVbaa++OIL64X8ww8/tPZThQoVCvr+rbfeSlT8hBBCCCFST5gqVqyYufnmmxMfGyGEEEKIVBamODfv6aefNt999505fPiwufrqq81jjz2mHXxCCCGEyLHEZDM1dOhQe4TLaaedZs/Le/bZZ639lBBCCCFETiUmYeqVV14xzz//vHXMyXl4HHSMryk0VkIIIYQQOZGYhCkOHeZAY0fTpk1Nrly5zJYtW7IibkIIIYQQqSVM4QqBI2NC/U7hyFMIIYQQIicSkwG653nmjjvuMPnz5w/cw4Fn9+7dg9wjyDWCEPGRa3CuDMN4g7wTEheR3KguCXGSCVOdOnVKc+/vf/97IuMjhBBCCJG6wtSkSZOyLiZCCCGEEDnlOBkhhBBCCPH/kDAlhBBCCBEHEqaEEEIIIeJAwpQQQgghRBxImBJCCCGEiAMJU0IIIYQQcSBhSgghhBAiDiRMCSGEEELEgYQpIYQQQog4kDAlhBBCCJHswtS4ceNMpUqVTIECBUz9+vXNsmXL0g0/ffp0U7VqVRu+Ro0aZvbs2YHvjhw5Yh566CF7n8OXy5QpYzp27Gi2bNlyAlIihBBCiJxGtgtT06ZNM3379jWDBg0yK1euNDVr1jTNmzc3O3bsCBt+8eLFpn379qZr165m1apVplWrVvZas2aN/f7AgQP2OQMHDrT/v/XWW2b9+vXmxhtvPMEpE0IIIUROINuFqVGjRplu3bqZzp07mwsuuMCMHz/eFCxY0EycODFs+DFjxphrrrnG9OvXz1SrVs0MGTLE1K5d24wdO9Z+X7RoUTN37lzTtm1bU6VKFXPppZfa71asWGE2btx4glMnhBBCiFQnb3a+/PDhw1bIGTBgQOBe7ty5TdOmTc2SJUvC/ob7aLL8oMmaOXNmxPfs3bvX5MqVyxQrViyBsRdCiNQj1+BcGYbxBnknJC5CJAvZKkzt2rXLHDt2zJQqVSroPp/XrVsX9jfbtm0LG5774Th48KC1oWJpsEiRImHDHDp0yF6Offv2ZSI1QgghhMiJZPsyX1aCMTrLfZ7nmRdeeCFiuGHDhtnlQXeVL1/+hMZTCCGEEMlLtgpTJUqUMHny5DHbt28Pus/n0qVLh/0N96MJ7wSpX375xdpQRdJKAcuMLAW6a9OmTXGlSwghhBA5h2xd5suXL5+pU6eOmTdvnt2RB8ePH7efe/XqFfY3DRo0sN/fd999gXsIS9wPFaS+//57s2DBAnPGGWekG4/8+fPbS4isQnYoQgiRumSrMAUYk3fq1MnUrVvX1KtXz4wePdrs37/f7u4DfESVLVvWLsVB7969TePGjc3IkSNNixYtzNSpU83y5cvNhAkTAoLULbfcYt0izJo1y9pkOXuq4sWLWwFOCCGEECJlhKl27dqZnTt3mkcffdQKPbVq1TJz5swJGJnjzoAdfo6GDRuayZMnm0ceecQ8/PDDpnLlynYnX/Xq1e33mzdvNu+88479m2f5QUt15ZVXntD0CSGEECK1yXZhCljSi7Sst3DhwjT32rRpY69w4Ekdg3MhhBBCiBNBSu/mE0IIIYTIaiRMCSGEEELEgYQpIYQQQog4kDAlhBBCCJHsBuhCCCGSD/lPE+L/Ic2UEEIIIUQcSJgSQgghhIgDCVNCCCGEEHEgYUoIIYQQIg4kTAkhhBBCxIF28wmRSbSTSQghBEgzJYQQQggRBxKmhBBCCCHiQMt8Qgghshwti4tURpopIYQQQog4kDAlhBBCCBEHEqaEEEIIIeJAwpQQQgghRBxImBJCCCGEiAMJU0IIIYQQcSDXCELEsHUbtH1biKxHrhREMiHNlBBCCCFEHEiYEkIIIYSIAwlTQgghhBBxIJspIYQQSY3sq0R2I82UEEIIIUQcSDMlUhrNWIUQQuQIzdS4ceNMpUqVTIECBUz9+vXNsmXL0g0/ffp0U7VqVRu+Ro0aZvbs2UHfe55nHn30UXPWWWeZU0891TRt2tR8//33WZwKIYQQyTDBiuYSIqmEqWnTppm+ffuaQYMGmZUrV5qaNWua5s2bmx07doQNv3jxYtO+fXvTtWtXs2rVKtOqVSt7rVmzJhBmxIgR5tlnnzXjx483n3/+uSlUqJB95sGDB09gyoQQQgiRE8j2Zb5Ro0aZbt26mc6dO9vPCEDvvfeemThxounfv3+a8GPGjDHXXHON6devn/08ZMgQM3fuXDN27Fj7W7RSo0ePNo888ohp2bKlDfPKK6+YUqVKmZkzZ5pbb731BKdQJBot3QkhThTqb8RJL0wdPnzYrFixwgwYMCBwL3fu3HZZbsmSJWF/w300WX7QOiEowYYNG8y2bdvsMxxFixa1y4f8VsKUEEKIrECCV84lW4WpXbt2mWPHjlmtkR8+r1u3LuxvEJTChee++97dixQmlEOHDtnLsXfvXvv/vn37MpUuYUzRYUUzDLN3wN6Yw1qiWK0NlF2Cw2bls4PqWzamUfHIeWlUPLInjVnaT4qYcOXC6lam8LKRzZs3E2tv8eLFQff79evn1atXL+xvTjnlFG/y5MlB98aNG+eVLFnS/v3ZZ5/ZZ27ZsiUoTJs2bby2bduGfeagQXaqoEuXLl26dOnKwdemTZsyJc9kq2aqRIkSJk+ePGb79u1B9/lcunTpsL/hfnrh3f/cYzefP0ytWrXCPpNlRv/S4fHjx82ePXvMGWecYXLlynVCJOLy5cubTZs2mSJFiphUJNXTmOrpA6UxNVAak59UT192pBGN1B9//GHKlCmTqd9nqzCVL18+U6dOHTNv3jy7I88JMnzu1atX2N80aNDAfn/fffcF7mGAzn04++yzrUBFGCc8USjs6rv77rvDPjN//vz28lOsWDFzoqHCpGrDyClpTPX0gdKYGiiNyU+qp+9EpxH76qTdzYdGqFOnTqZu3bqmXr16dife/v37A7v7OnbsaMqWLWuGDRtmP/fu3ds0btzYjBw50rRo0cJMnTrVLF++3EyYMMF+jyYJQeuJJ54wlStXtsLVwIEDrbTpBDYhhBBCiESR7cJUu3btzM6dO62TTQzE0SbNmTMnYEC+ceNGu8PP0bBhQzN58mTr+uDhhx+2AhM7+apXrx4I8+CDD1qB7M477zS///67ufzyy+0zcfIphBBCCJFSwhSwpBdpWW/hwoVp7rVp08ZekUA79fjjj9srGWCJEaeloUuNqUSqpzHV0wdKY2qgNCY/qZ6+ZExjLqzQszsSQgghhBDJSrYfJyOEEEIIkcxImBJCCCGEiAMJU0IIIYQQcSBhKpsZN26cqVSpkt1pyPmBy5YtM6nCY489ZjcD+K+qVauaZObjjz82N9xwg3W1QXrcmZAOTBDZmYrD2FNPPdWeEfn999+bVErjHXfckaZcOXw8WcDNyiWXXGIKFy5sSpYsaV2mrF+/PijMwYMHTc+ePa3j3tNOO83cfPPNaZwFn8xEk8Yrr7wyTTl2797dJAsvvPCCueiiiwJ+iPA1+P7776dMGUaTxmQvw1CGDx8ecG+UbOUoYSobmTZtmvWzxY6FlStXmpo1a9pDm3fs2GFShQsvvNBs3bo1cH366acmmcHlBuWEEByOESNGmGeffdaMHz/eOootVKiQLVM6hFRJIyA8+ct1ypQpJllYtGiR7ZyXLl1qHf4eOXLENGvWzKbb0adPH/Puu++a6dOn2/BbtmwxN910k0mlNEK3bt2CypH6myyUK1fODr4rVqywvgavvvpq07JlS7N27dqUKMNo0pjsZejniy++MP/+97+t8OgnacoxU4fQiITA+YM9e/YMfD527JhXpkwZb9iwYV4qwJmHNWvW9FIVms+MGTMCn48fP+6VLl3ae/rppwP3fv/9dy9//vzelClTvFRII3Tq1Mlr2bKllyrs2LHDpnPRokWBMuMM0OnTpwfCfPvttzbMkiVLvFRIIzRu3Njr3bu3l0qcfvrp3osvvpiSZRiaxlQqwz/++MOrXLmyN3fu3KA0JVM5SjOVTRw+fNjONlgGcuCclM9LliwxqQJLXCwXnXPOOaZDhw7WCWuqsmHDBut41l+mHE/A8m0qlanz/8byUZUqVewxTbt37zbJyt69e+3/xYsXt//TLtHk+MuR5ekKFSokbTmGptHx2muv2TNScXrMGaUHDhwwycixY8fsaRho3lgKS8UyDE1jKpVhz5497Ykm/vKCZCrHk8JpZ05k165dtnE4T+8OPq9bt86kAggRL7/8sh1wUT8PHjzYNGrUyKxZs8bacqQaCFIQrkzdd6kAS3yo2Tmq6ccff7QnEVx77bW2c+Pg8mSCs0Cxz7jssssCpyhQVpwbGno+Z7KWY7g0wm233WYqVqxoJzurV682Dz30kLWreuutt0yy8PXXX1vBgmV07GlmzJhhLrjgAvPll1+mTBlGSmOqlOHUqVOtmQvLfKEkU1uUMCWyDAZYB+vgCFc0/Ndff9107do1W+MmMs+tt94a+LtGjRq2bM8991yrrWrSpIlJthkxwn2y2/JlJo0ct+UvRzZNUH4IyJRnMsBEDcEJzdsbb7xhz3nFriaViJRGBKpkL8NNmzbZ83ax60v24960zJdNoJZlFh+6K4HPpUuXNqkIs4vzzz/f/PDDDyYVceWWk8oUWMKlPidbuXKE1axZs8yCBQusoa+DsmIZnnM9k70cI6UxHEx2IJnKEa3FeeedZ+rUqWN3MLJxYsyYMSlVhpHSmApluGLFCrvhqnbt2iZv3rz2QlBkEw9/o4FKlnKUMJWNDYTGMW/evCB1PJ/96+GpxJ9//mlnTMyeUhGWvWjg/jLdt2+f3dWXqmUKv/76q7WZSpZyxa4eIYPlkvnz59ty80O7POWUU4LKkaUT7P2SpRwzSmM40H5AspRjOOhDDx06lBJlmFEaU6EMmzRpYpcxibe76tata+1r3d9JU47ZbQGfk5k6dard6fXyyy9733zzjXfnnXd6xYoV87Zt2+alAvfff7+3cOFCb8OGDd5nn33mNW3a1CtRooTdWZTMu05WrVplL5rPqFGj7N+//PKL/X748OG2DN9++21v9erVdtfb2Wef7f31119eKqSR7x544AG7k4Zy/eijj7zatWvbnTgHDx70koG7777bK1q0qK2bW7duDVwHDhwIhOnevbtXoUIFb/78+d7y5cu9Bg0a2CtZyCiNP/zwg/f444/btFGO1NdzzjnHu+KKK7xkoX///nZ3IvGnrfE5V65c3ocffpgSZZhRGlOhDMMRukMxWcpRwlQ289xzz9mKki9fPusqYenSpV6q0K5dO++ss86yaStbtqz9TAeQzCxYsMAKGKEX7gKce4SBAwd6pUqVsoJykyZNvPXr13upkkYG42bNmnlnnnmm3bJcsWJFr1u3bkk1AQiXNq5JkyYFwiD89ujRw25DL1iwoNe6dWsrjKRKGjdu3GgH3eLFi9t6et5553n9+vXz9u7d6yULXbp0sfWP/oX6SFtzglQqlGFGaUyFMoxGmEqWcszFP9mtHRNCCCGESFZkMyWEEEIIEQcSpoQQQggh4kDClBBCCCFEHEiYEkIIIYSIAwlTQgghhBBxIGFKCCGEECIOJEwJIYQQQsSBhCkhhBBCiDiQMCWESDp+/vlnkytXrsBZZCcD69atM5deeqkpUKCAqVWrVtgwV155pbnvvvsS/u6XX37ZHiQuhMgeJEwJIWLmjjvusMLM8OHDg+7PnDnT3s+JDBo0yBQqVMgexOo/mFUIkfpImBJCZAo0ME899ZT57bffTKpw+PDhTP/2xx9/NJdffrmpWLGiOeOMMxIaLyHEyY2EKSFEpmjatKkpXbq0GTZsWMQwjz32WJolr9GjR5tKlSoFablatWplnnzySVOqVCm7XPX444+bo0ePmn79+pnixYubcuXKmUmTJoVdWmvYsKEV7KpXr24WLVoU9P2aNWvMtddea0477TT77Ntvv93s2rUraNmtV69edumtRIkSpnnz5mHTcfz4cRsn4pE/f36bpjlz5gS+Rxu3YsUKG4a/SXckSBfvLFq0qH3nwIEDOXA+8P2hQ4fMAw88YMqWLWs1XfXr1zcLFy5Ms6xXoUIFU7BgQdO6dWuze/fuoO+/+uorc9VVV5nChQubIkWKmDp16pjly5dHjJMQIj4kTAkhMkWePHmsAPTcc8+ZX3/9Na5nzZ8/32zZssV8/PHHZtSoUXbJ7Prrrzenn366+fzzz0337t3NXXfdleY9CFv333+/WbVqlWnQoIG54YYbAoLF77//bq6++mpz8cUXW0EC4Wf79u2mbdu2Qc/473//a/Lly2c+++wzM378+LDxGzNmjBk5cqR55plnzOrVq63QdeONN5rvv//efr9161Zz4YUX2rjwN8JQJHhf3rx5zbJly+xzSe+LL74Y+B5Ba8mSJWbq1Kn2XW3atDHXXHNN4F3kR9euXW04bMYQmp544omgd3To0MEKfl988YUV8vr3729OOeWUmMtFCBElnhBCxEinTp28li1b2r8vvfRSr0uXLvbvGTNmoGIJhBs0aJBXs2bNoN/+61//8ipWrBj0LD4fO3YscK9KlSpeo0aNAp+PHj3qFSpUyJsyZYr9vGHDBvue4cOHB8IcOXLEK1eunPfUU0/Zz0OGDPGaNWsW9O5NmzbZ361fv95+bty4sXfxxRdnmN4yZcp4Q4cODbp3ySWXeD169Ah8Jp2kNz14X7Vq1bzjx48H7j300EP2Hvzyyy9enjx5vM2bNwf9rkmTJt6AAQPs3+3bt/euu+66oO/btWvnFS1aNPC5cOHC3ssvv5xhuoQQiUGaKSFEXGA3hbbl22+/zfQz0Orkzv1/3RFLcjVq1AjSgmGHtGPHjqDfoY1yoO2pW7duIB4sdS1YsMAu8bmratWqAfsmB0tg6bFv3z6rNbvsssuC7vM5M2lmx5/fSJ80oHU6duyY+frrr+3/559/flC8Wb50ceadLP1Fygfo27ev+cc//mGXYtkk4E+vECLx5M2CZwohchBXXHGFXfYaMGCAtX/yg4DktweCI0eOpHlG6BIUwka4e9guRcuff/5pl/0Q9kI566yzAn9jl3SyQJwRHFma438/CFXRgs3WbbfdZt577z3z/vvv22VTlg2xrxJCJB4JU0KIuEH7gVF2lSpVgu6feeaZZtu2bVagctqYRPqGWrp0qRXmnGE3Qgi2RFC7dm3z5ptvWmN3tFaZBQPuMmXKWJuqxo0bB+7zuV69ejE/D5un0DRUrlzZCk/Yd6GZQgPXqFGjsL+vVq1a2GeEgnaLq0+fPqZ9+/bWgF/ClBBZg5b5hBBxw5IcRs/PPvts0H12y+3cudOMGDHCLjWNGzfOakoSBc+bMWOG3dXXs2dP66ahS5cu9js+79mzxwoSGGLz/g8++MB07tzZCiyxgKE7Gq5p06ZZP1IYdCMU9u7dO+Y4b9y40S7D8ZwpU6ZYA373HIQf8rFjx47mrbfeMhs2bLCG6uyYRMsE9957rzWmxxie5cGxY8cG7Sz866+/rEDJDsBffvnFCn2kHyFMCJE1SJgSQiQE3AKELsMxgD///PNW6KlZs6YVDNLb6ZYZjRgXz/7000/NO++8Y90NgNMmITg1a9bMCny4QMD1gt8+KxoQYBCA2K3HcxBeeBcapVhBUELgQauFwIcgdeeddwa+R4NEGN6Fpg+3EQhDuEJwNlf/+c9/7E5A0v3hhx+aRx55JPB7NFzsaOQZCGfsXsQ9xODBg2OOqxAiOnJhhR5lWCGEEEIIEYI0U0IIIYQQcSBhSgghhBAiDiRMCSGEEELEgYQpIYQQQog4kDAlhBBCCBEHEqaEEEIIIeJAwpQQQgghRBxImBJCCCGEiAMJU0IIIYQQcSBhSgghhBAiDiRMCSGEEELEgYQpIYQQQgiTef4/7t0cb2L+1NYAAAAASUVORK5CYII=", - "text/plain": [ - "
" + "cell_type": "code", + "execution_count": 30, + "metadata": { + "execution": { + "iopub.execute_input": "2026-02-23T08:42:52.516252Z", + "iopub.status.busy": "2026-02-23T08:42:52.516137Z", + "iopub.status.idle": "2026-02-23T08:42:52.977283Z", + "shell.execute_reply": "2026-02-23T08:42:52.976808Z" + } + }, + "outputs": [ + { + "data": { + "image/png": "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esm1a9e09Sl07txZizTtjRx27dqlL/z9xx9/6N/2XLVBgwbJ+vXr5ejRo7Jx40Zp3bq15vB16NAh3ukkIiIicnXwhqCpb9++8tlnn2mLTtQtQ50yBFRx0a5dO5k0aZIMHz5cKleurIEYGhqYRgxoJYp+2oyTJ09KlSpV9IXp+C7+fuGFFzzznDhxQgO1UqVKyXPPPSf33XefbN68WfLkyROfTSUiIiIKKxGWZVkJWQA61507d64sWrRI33fs2FF69OihHe66FboKQatTNF7Ili1bqJNDycxjbfskeBmrls505TKJiMLRFZc99xPc2rRq1apatImcONQvQwe7qMuG7jkwnBURERERhUHwdvv2bS02ffzxx6Vo0aLyzTffyIwZM7S1KOqgYRq67CAiIiKiEHcV0q9fPy0mRYnr888/LxMmTJDy5ct7Ps+cObPWR8MoB0REREQU4uDt119/lXfeeUeeeeYZv/2joR+3xOhShIiIiIgSWGwaGRmpRaK+gdudO3dkw4YNnsHhGzZsGJ/FExEREVFiBm+PPvqoXLx4Mdp0tNLAZ0REREQURsWmqOsWERERbfqFCxe0vhtRcsHuMoiIyNXBG+q4AQK3rl27ehWb3r17V3bv3i1169ZN/FQSERERUdyDN3RgZ3LesmbNKhkzZvQaq7R27drSs2fPuCySiIiIiIIVvGEkBShWrJiOIcoiUiIiIiIX1HlDa1MiIiIiCuPgDcNgrV69WnLmzKmDwTs1WLCPd0pEREREIQzeWrZs6Wmg0KpVqyAkhYiIiIgSLXizF5Wy2JSIiIjIZQPTExEREVEY57yhrltM9dzsnEZfICIiIqIkDN6mTp2aCKsjIiIioiQJ3rp06ZKgFRERERFREgZvV65ckWzZsnn+jomZj4iIiIhCWOft1KlTkjdvXsmRI4dj/TczYD3GOSUiIiKiEAZva9askVy5cunfa9euDUJSiIiIiCjRgreGDRs6/k1EREREYT62Kfz555/ywQcfyL59+/R92bJlpVu3bp7cOSIiIiIKk056N2zYIMWKFZPp06drEIcX/i5evLh+RkRERERhlPPWp08fadeuncyaNUtSp06t09BIoXfv3vrZL7/8ktjpJCIiIqL45rwdOnRIBg4c6AncAH8PGDBAPyMiIiKiMAreqlat6qnrZodplSpVSox0EREREVFCik13797t+fvll1+W/v37ay5b7dq1ddrmzZtl5syZMm7cuEAXSURERETBCt4qV66sHfCiI15jyJAh0ebr2LGj1ocjInLyWNs+CV7GqqUzEyUtRETJOng7cuRIcFNCRERERIkXvBUtWjTQWYmIiIgo3DrphV9//VWOHTsmUVFRXtOffvrphKaLiIiIiBKrten//vc/bVVavnx5eeKJJ6RVq1b6at26tb7iAo0c0OFvhgwZpFatWrJ161a/8+7du1fatGmj86P+3dSpUxO8TCIiIqJkH7yhpSlGUzh79qxkypRJgyqMrFC9enVZt25dwMtZsmSJ9g0XGRkpO3bs0ICwWbNmulwn169flwceeEBbtObPnz9RlklERESU7IO3TZs2yahRoyR37tySKlUqfdWvX1/Gjh2r3YgEasqUKdKzZ08dExVjo86ePVuDwQ8//NBx/ho1asjEiROlffv2kj59+kRZJhEREVGyD94wFFbWrFn1bwRwJ0+e9DRqOHDgQEDLQD257du3S5MmTf4vMalS6XsEh/ER32XeunVLrly54vUiIiIiSjbBG+q6/fzzz/o36pRNmDBBfvzxR82NQ7FmIM6fP69BYL58+bym4/3p06fjk6x4LxM5htmzZ/e8ihQpEq/1ExEREYVl8Pbmm2/KvXv39G8EbOgDrkGDBvL111/L9OnTxW2GDh0qly9f9ryOHz8e6iQRERERJV5XIWgAYJQoUUL2798vFy9elJw5c2or0ECguBWD2Z85c8ZrOt77a4wQrGWi/py/OnRERERErs95s0MuFV65cuUKOHCDdOnSSbVq1WT16tWeacjNw/s6derEKy3BWCYRERGR64O3O3fuyLBhw7R+GPpTwwt/ozj19u3bAS8HXXrMmTNH5s+fL/v27ZNevXrJtWvXtKUodO7cWYs07Q0Sdu3apS/8/ccff+jfhw4dCniZRERERCmu2LRfv37yxRdfaEMFk6OF1pwjRoyQCxcuyKxZswJaDgawP3funAwfPlwbFFSuXFlWrlzpaXCA0RvQWtRAq9YqVap43k+aNElfDRs29PQvF9syiYiIiFJc8LZw4UJZvHixtGjRwjOtYsWK2kqzQ4cOAQdv0LdvX3058e3wFzl8lmUlaJlEREREKa7YFJX7EUj5wqgLqHdGRERERGEUvCFXa/To0dq5rYG/33rrLeZ4EREREYVDsekzzzzj9f67776TwoUL69ihgE570YigcePGiZ9KIiIiIopb8IbWpHZt2rTxes9RCYiIiIjCKHibO3ducFNCRERERMFpbWqgSw4zEH2pUqUkT548CVkcEREREQWjwQI6ve3evbsUKFBAHn74YX0VLFhQevToIdevX4/PIomIiIgoWMEbRjFYv369fPXVV3Lp0iV9ffnllzpt4MCB8VkkEREREQWr2PTzzz+Xzz77TB555BHPtMcff1wyZswozz33XJw66SUiIiKiIOe8oWjUabipvHnzstiUiIiIKNyCN4xnGhkZKTdv3vRMu3HjhowcOdIz1ikRERERhUmx6dSpU6V58+bROunNkCGDfPPNN4mdRiIiIiJKSPBWoUIFOXjwoHzyySeyf/9+nYYB6Tt16qT13oiIiIgoTIK327dvS+nSpWXFihXSs2fP4KSKiIiIiBKnzlvatGm96roRERERUZg3WOjTp4+MHz9e7ty5k/gpIiIiIqLErfP2008/yerVq+Xbb7/V+m+ZM2f2+vyLL76Iz2KJiIiIKBjBW44cOaRNmzbx+SoRERERJVXwdu/ePZk4caL89ttvEhUVJY0aNZIRI0awhSmF3GNt+yR4GauWzkyUtBAREYVNnbe33npL3njjDcmSJYsUKlRIpk+frvXfiIiIiCgMg7cFCxbIu+++qx3xLl++XAemR19vyJEjIiIiojAL3o4dO6YD0BtNmjSRiIgIOXnyZDDSRkREREQJCd7QNQiGwPLt9w0d9xIRERFRmDVYsCxLunbtKunTp/dMQ4e9L730kld3IewqhIiIiCgMgrcuXbpEm/a3v/0tMdNDRERERIkVvM2dOzcusxMRERFROAyPRUREREShweCNiIiIyEUYvBERERG5CIM3IiIiIhdh8EZERESUXFubBsvMmTN1wPvTp09LpUqV5J133pGaNWv6nX/p0qUybNgwOXr0qJQsWVLGjx/vNfID+qKbP3++13eaNWsmK1euDOp2EFFoPNY24WMsr1o6M1HSQkSU7HPelixZIgMGDJDIyEjZsWOHBm8ItM6ePes4/8aNG6VDhw7So0cP2blzp7Rq1Upfe/bs8ZqvefPmcurUKc9r0aJFSbRFRERERMk4eJsyZYr07NlTunXrJmXLlpXZs2dLpkyZ5MMPP3Scf9q0aRqYDR48WMqUKSOjR4+WqlWryowZM7zmwygQ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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import numpy as np\n", + "from patientflow.viz.probability_distribution import plot_prob_dist\n", + "from patientflow.viz.utils import format_prediction_time\n", + "\n", + "title = (\n", + " f'Probability distribution for number of beds needed by the '\n", + " f'{len(snapshot_ids)} patients\\n'\n", + " f'in the ED at {format_prediction_time(prediction_time)} '\n", + " f'on {snapshot_date}'\n", + ")\n", + "plot_prob_dist(pmf_array, title, include_titles=True)" ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "title = (\n", - " f'Probability distribution for number of beds needed for patients\\n'\n", - " f'who will arrive after {format_prediction_time(prediction_time)} '\n", - " f'and need a bed within 8 hours'\n", - ")\n", - "plot_prob_dist(yta_distribution, title, include_titles=True, truncate_at_beds=40, bar_colour='green')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Because this distribution is based on a Poisson model, the `DemandPredictor` can regenerate it from just the Poisson mean (lambda). The model provides a `predict_mean()` method for this purpose. This is what `build_service_data()` uses internally in the 4x_ notebooks — it stores just the Poisson rate in the `FlowInputs` container, and the `DemandPredictor` reconstructs the full distribution when needed." - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": { - "execution": { - "iopub.execute_input": "2026-02-23T08:42:53.105599Z", - "iopub.status.busy": "2026-02-23T08:42:53.105504Z", - "iopub.status.idle": "2026-02-23T08:42:53.119373Z", - "shell.execute_reply": "2026-02-23T08:42:53.118988Z" - } - }, - "outputs": [ + }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "Yet-to-arrive Poisson rate (lambda): 18.618\n" - ] - } - ], - "source": [ - "# predict_mean() returns just the Poisson rate (a single float)\n", - "yta_lambda = yta_model.predict_mean(prediction_context, x1=x1, y1=y1, x2=x2, y2=y2)\n", - "\n", - "print(f'Yet-to-arrive Poisson rate (lambda): {yta_lambda:.3f}')\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "We can wrap this Poisson rate in a `FlowInputs` container. The key difference from Step 2 is that `flow_type` is `\"poisson\"` and `distribution` is a float (the rate) rather than a numpy array." - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": { - "execution": { - "iopub.execute_input": "2026-02-23T08:42:53.120630Z", - "iopub.status.busy": "2026-02-23T08:42:53.120552Z", - "iopub.status.idle": "2026-02-23T08:42:53.134389Z", - "shell.execute_reply": "2026-02-23T08:42:53.134026Z" - } - }, - "outputs": [ + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This is exactly the kind of result we produced in the 3x_ notebooks — a numpy array of probabilities. Now let's see how `patientflow` wraps this in a named container." + ] + }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "Flow ID: ed_yta\n", - "Flow type: poisson\n", - "Display name: ED yet-to-arrive admissions\n", - "Distribution: 18.618075334578297 (Poisson lambda)\n" - ] - } - ], - "source": [ - "ed_yta_flow = FlowInputs(\n", - " flow_id=\"ed_yta\",\n", - " flow_type=\"poisson\",\n", - " distribution=yta_lambda,\n", - " display_name=\"ED yet-to-arrive admissions\"\n", - ")\n", - "\n", - "print(f'Flow ID: {ed_yta_flow.flow_id}')\n", - "print(f'Flow type: {ed_yta_flow.flow_type}')\n", - "print(f'Display name: {ed_yta_flow.get_display_name()}')\n", - "print(f'Distribution: {ed_yta_flow.distribution} (Poisson lambda)')\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Both PMF and Poisson flows use the same `FlowInputs` container, distinguished only by `flow_type`. This uniform interface means downstream code can handle any flow without special-casing." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Step 4: Group flows into a `ServicePredictionInputs`\n", - "\n", - "A hospital service (e.g. \"medical\") has multiple sources of incoming patients and potentially outgoing patients too. `ServicePredictionInputs` groups all of these into a single object, organised as **inflows** and **outflows**.\n", - "\n", - "Let's build one using the two flows we just created. For the departure flows, we'll create simple fake PMFs from a Poisson distribution to represent expected discharges. For transfers and other inflows where we don't have models, we use zero placeholders — a PMF of `[1.0]` (certainly zero patients) or a Poisson rate of `0.0`." - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": { - "execution": { - "iopub.execute_input": "2026-02-23T08:42:53.136112Z", - "iopub.status.busy": "2026-02-23T08:42:53.136001Z", - "iopub.status.idle": "2026-02-23T08:42:53.151196Z", - "shell.execute_reply": "2026-02-23T08:42:53.150877Z" - } - }, - "outputs": [ + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Step 2: Wrap the PMF in a `FlowInputs` container\n", + "\n", + "A `FlowInputs` object is a lightweight, immutable container that holds a single source of patient flow. It adds metadata to the raw distribution:\n", + "\n", + "- **`flow_id`** — a unique identifier (e.g. `\"ed_current\"`)\n", + "- **`flow_type`** — either `\"pmf\"` or `\"poisson\"`, so downstream code knows how to handle it\n", + "- **`display_name`** — an optional human-readable label\n", + "- **`aspirational`** — whether the flow reflects demand under target performance assumptions rather than empirically observed patterns (default `False`; see notebook 4d for evaluation implications)\n", + "\n", + "The distribution itself is stored in the `distribution` attribute — exactly the same numpy array we just plotted." + ] + }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "ServicePredictionInputs(service='medical')\n", - " INFLOWS:\n", - " Admissions from current ED PMF[2:12]: [0.007, 0.026, 0.071, 0.135, 0.191, 0.204, 0.169, 0.109, 0.056, 0.022] (E=6.9 of 21 patients in ED)\n", - " ED yet-to-arrive admissions λ = 18.618\n", - " Non-ED emergency admissions λ = 0.000\n", - " Elective admissions λ = 0.000\n", - " Elective transfers from other services PMF[0:1]: [1.000] (E=0.0)\n", - " Emergency transfers from other services PMF[0:1]: [1.000] (E=0.0)\n", - " OUTFLOWS:\n", - " Emergency inpatient departures PMF[0:10]: [0.007, 0.034, 0.084, 0.140, 0.175, 0.175, 0.146, 0.104, 0.065, 0.036] (E=5.0 of 29 emergency patients in service)\n", - " Elective inpatient departures PMF[0:10]: [0.135, 0.271, 0.271, 0.180, 0.090, 0.036, 0.012, 0.003, 0.001, 0.000] (E=2.0 of 19 elective patients in service)\n" - ] - } - ], - "source": [ - "from patientflow.predict.service import ServicePredictionInputs\n", - "from scipy.stats import poisson as poisson_dist\n", - "\n", - "prediction_window = timedelta(hours=8)\n", - "\n", - "# Create fake departure PMFs from Poisson distributions\n", - "emergency_departure_pmf = poisson_dist.pmf(np.arange(30), mu=5) # ~5 emergency discharges expected\n", - "elective_departure_pmf = poisson_dist.pmf(np.arange(20), mu=2) # ~2 elective discharges expected\n", - "\n", - "service_inputs = ServicePredictionInputs(\n", - " service_id='medical',\n", - " prediction_window=prediction_window,\n", - " inflows={\n", - " 'ed_current': ed_current_flow,\n", - " 'ed_yta': ed_yta_flow,\n", - " 'non_ed_yta': FlowInputs(\n", - " flow_id='non_ed_yta', flow_type='poisson',\n", - " distribution=0.0, display_name='Non-ED emergency admissions',\n", - " ),\n", - " 'elective_yta': FlowInputs(\n", - " flow_id='elective_yta', flow_type='poisson',\n", - " distribution=0.0, display_name='Elective admissions',\n", - " ),\n", - " 'elective_transfers': FlowInputs(\n", - " flow_id='elective_transfers', flow_type='pmf',\n", - " distribution=np.array([1.0]),\n", - " display_name='Elective transfers from other services',\n", - " ),\n", - " 'emergency_transfers': FlowInputs(\n", - " flow_id='emergency_transfers', flow_type='pmf',\n", - " distribution=np.array([1.0]),\n", - " display_name='Emergency transfers from other services',\n", - " ),\n", - " },\n", - " outflows={\n", - " 'emergency_departures': FlowInputs(\n", - " flow_id='emergency_departures', flow_type='pmf',\n", - " distribution=emergency_departure_pmf,\n", - " display_name='Emergency inpatient departures',\n", - " ),\n", - " 'elective_departures': FlowInputs(\n", - " flow_id='elective_departures', flow_type='pmf',\n", - " distribution=elective_departure_pmf,\n", - " display_name='Elective inpatient departures',\n", - " ),\n", - " },\n", - ")\n", - "\n", - "print(service_inputs)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The printed representation shows all inflows and outflows at a glance. The `ed_current` flow shows the PMF from Step 1, and the `ed_yta` flow shows the Poisson rate from Step 3. The departure flows use fake Poisson PMFs (with expected values of ~5 and ~2 respectively), and the transfer flows are zero placeholders.\n", - "\n", - "In a production system, these departure distributions would come from discharge prediction models, and the transfer flows would also be populated. You'll see this in the 4x_ notebooks." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Step 5: Use `DemandPredictor` to generate a prediction\n", - "\n", - "The `DemandPredictor` takes a `ServicePredictionInputs` and convolves the selected flows into a combined probability distribution. This is the same convolution we performed manually in notebook 3e (where we convolved multiple Poisson distributions using `np.convolve`), but wrapped in a method that handles both PMF and Poisson flows automatically.\n", - "\n", - "Let's predict demand using only the current ED patients first." - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": { - "execution": { - "iopub.execute_input": "2026-02-23T08:42:53.152652Z", - "iopub.status.busy": "2026-02-23T08:42:53.152571Z", - "iopub.status.idle": "2026-02-23T08:42:53.170209Z", - "shell.execute_reply": "2026-02-23T08:42:53.169810Z" - } - }, - "outputs": [], - "source": [ - "from patientflow.predict.demand import DemandPredictor\n", - "from patientflow.predict.demand import FlowSelection\n", - "\n", - "predictor = DemandPredictor(k_sigma=8.0)\n", - "\n", - "# Predict using only the current ED patients\n", - "current_ed_bundle = predictor.predict_service(\n", - " inputs=service_inputs,\n", - " flow_selection=FlowSelection.custom(\n", - " include_ed_current=True,\n", - " include_ed_yta=False,\n", - " include_non_ed_yta=False,\n", - " include_elective_yta=False,\n", - " include_transfers_in=False,\n", - " include_departures=False,\n", - " cohort='emergency'\n", - " )\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The result is a `PredictionBundle` containing a `DemandPrediction` for arrivals. Let's look at the arrivals prediction — this corresponds to the PMF we started with." - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": { - "execution": { - "iopub.execute_input": "2026-02-23T08:42:53.171695Z", - "iopub.status.busy": "2026-02-23T08:42:53.171616Z", - "iopub.status.idle": "2026-02-23T08:42:53.186969Z", - "shell.execute_reply": "2026-02-23T08:42:53.186533Z" - } - }, - "outputs": [ + "cell_type": "code", + "execution_count": 31, + "metadata": { + "execution": { + "iopub.execute_input": "2026-02-23T08:42:52.978607Z", + "iopub.status.busy": "2026-02-23T08:42:52.978477Z", + "iopub.status.idle": "2026-02-23T08:42:53.015054Z", + "shell.execute_reply": "2026-02-23T08:42:53.014672Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Flow ID: ed_current\n", + "Flow type: pmf\n", + "Display name: Admissions from current ED\n", + "Distribution: numpy array of shape (22,)\n", + "Same data? True\n" + ] + } + ], + "source": [ + "from patientflow.predict.service import FlowInputs\n", + "\n", + "ed_current_flow = FlowInputs(\n", + " flow_id=\"ed_current\",\n", + " flow_type=\"pmf\",\n", + " distribution=pmf_array,\n", + " display_name=\"Admissions from current ED\"\n", + ")\n", + "\n", + "print(f'Flow ID: {ed_current_flow.flow_id}')\n", + "print(f'Flow type: {ed_current_flow.flow_type}')\n", + "print(f'Display name: {ed_current_flow.get_display_name()}')\n", + "print(f'Distribution: numpy array of shape {ed_current_flow.distribution.shape}')\n", + "print(f'Same data? {np.array_equal(ed_current_flow.distribution, pmf_array)}')" + ] + }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "Expectation: 6.9\n", - "Expected value: 7\n", - "Percentiles: {25: 6, 50: 7, 75: 8}\n", - "PMF shape: (22,)\n" - ] - } - ], - "source": [ - "arrivals = current_ed_bundle.arrivals\n", - "\n", - "print(f'Expectation: {arrivals.expectation:.1f}')\n", - "print(f'Expected value: {arrivals.mode}')\n", - "print(f'Percentiles: {arrivals.percentiles}')\n", - "print(f'PMF shape: {arrivals.probabilities.shape}')" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": { - "execution": { - "iopub.execute_input": "2026-02-23T08:42:53.188175Z", - "iopub.status.busy": "2026-02-23T08:42:53.188096Z", - "iopub.status.idle": "2026-02-23T08:42:53.241049Z", - "shell.execute_reply": "2026-02-23T08:42:53.240580Z" - } - }, - "outputs": [ + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The data inside `FlowInputs` is exactly the same PMF array. The container simply gives it a name and a type." + ] + }, { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAk4AAAEiCAYAAAAPh11JAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjMsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvZiW1igAAAAlwSFlzAAAPYQAAD2EBqD+naQAAP2RJREFUeJzt3QvcTWX+//8PyjGnknM5lEhORURJRaQTZQoph6Sp0AE1aeImGodoJGJGE5oppFIzTUMSmkKKpAOFUciZkJTj+j/e1/+39nftfe/bve6TfR9ez8djc++1117rWmuvtfZnX9fnulY+z/M8AwAAQKrypz4LAAAAhMAJAAAgJAInAACAkAicAAAAQiJwAgAACInACQAAICQCJwAAgJAInAAAAEIicAIAAAiJwAkJUbVqVevevXvk+aJFiyxfvnzu/+xaxni+//57V+4xY8ZkeXmmTZvm1qV15kZh9nda+J+N9ltq1q1bZ61bt7aSJUu697z11luZVg4grXL7uZ7TETjl4ZPSfxQuXNguuOAC69Onj+3YscNyknfffdeGDBmS6GIgh+vWrZt9+eWX9vTTT9vf//53a9SoUaKLlOe88MILoYJcX/AaFvu47777IvMpGA++dsYZZ1j16tXtd7/7nb3xxht24sQJS5Q//elPCQvSDx065K6d2enHak5xWqILgMR56qmnrFq1avbbb7/ZRx99ZJMmTXKByFdffWVFixY9pWW58sor7ddff7WCBQum6X0q78SJEwmekG467pYuXWp//OMf3Y8HJC5wKlOmTJpqHa+99lrr2rVrsun6IRhUqFAhe/HFFyOf9w8//GD/+te/XPB01VVX2dtvv20lSpSwRAROKkP79u2jpt91113WqVMnV+6sDJyGDh3q/tY+QHgETnlY27ZtI7+s77nnHjvrrLPs2WefdReRzp07x33PL7/8YsWKFcv0suTPn9/VfAGn2q5du9z/pUqVSnXerDr+sxt9qcb78XTs2DFXQ5PWHzhZRQHSnXfemep8p512WrL5hg8fbiNHjrSBAwdar169bNasWZZdFChQwD2QPdFUh4hrrrnG/b9x40b3v375qVp7w4YNdv3111vx4sWtS5cu7jVdPMeNG2cXXXSRC3jKlStnv//97+2nn36KWqbnee4CVblyZXchvvrqq+3rr79Otu6Ucpw++eQTt+7SpUu7L6x69erZc889FymfapskWBXvy+wypubPf/6zValSxYoUKWItWrRwNXex1q5d635hnnnmma5MClz/+c9/JptP69fnoWWpXCpfvCaFzz77zNq0aeN+qWte1SDefffdofKJbrzxRlfT2LhxY1cWNV+8/PLLyebdt2+fPfzww3bOOee4X8Dnn3++jRo1Kll5smJ/h1235tPxoBwlBUBqetO01KimUp+ZPProo+740b7xX9Pzb775xu644w53DF5xxRWRAGLYsGF23nnnuXLpPU888YQdPnw47n7Wca3PWp9R3bp1I8f5m2++6Z5rfzVs2NA+//zzVMvsb+8jjzzilq/1a1+q5mX37t0nzZGJd56ptqFOnTq2YsUKV/Orz0TbEszf0+fqb6v2R9hj2S/Hxx9/bP369bOzzz7bnce33HJLJGD195OOgcWLF0fO41NRC/L444+73LbZs2fbd999d9J5/evh//73P3fOaTsqVqzoau51TAdpnzVr1sz9GNVnrs/29ddfj5pH26hAfPr06ZFt9mvbUvr8/vOf/1jz5s3dunU9vuGGG5KdO345f/zxR1eTpb+13wcMGGDHjx9382i5miaqdfLX79fcb9++3Xr06OGOK33mFSpUsHbt2pFz9f9Q44QIBUiik92nLwhdJPSFoYuB/ytUX4g6uXVyPfjggy7YmjBhgrvw6yJ5+umnu/kGDx7sviQV/OixcuVKd6E6cuRIquWZP3+++9LRSfvQQw9Z+fLlbc2aNfbOO++45yrD1q1b3XzKS4l1KsroU8Dx888/W+/evV3Tp4I7BT7Km1EAIbrAXX755VapUiV3wdbF77XXXnMXN+Va6MvEv2gpmNC+9+f761//6i7AQTt37nTl1AVQ8ylg0IVNX8ZhrF+/3n3x9ezZ0wUaL730krvo6iKv4MeveVAQqIuw9ue5555rS5Yscb/St23b5r5Qs2p/h123vrR0UVcQqNyWCy+80ObMmeO2KTW33nqr228KQlTLqvLoiybotttusxo1arhmFf8LUjW0+sLT/uvfv78L8EeMGOGOT607dj8r8NI2qNZD59FNN91kkydPdgHKAw884ObT+2+//Xb79ttvXQ1sSg4ePOi+PLUuBcmXXHKJC5gUtGzZssUF0Wm1Z88eVwOt5iGV0T9mZerUqe6Yvvfee92XqAKlsMeyr2/fvi7wTEpKcseoPjs1i/q1PHquebTv1WQqwTKkROXyg8UgNbuFrRVTs9h7773nriOxTXyxFHhcd911dtlll9no0aNt7ty5bpt0riqA8un8v/nmm90PTR3XM2fOdMeRrl0KdkTXLB1H+uGifSsKTlOi+XVM63qsHw86P5ReoWuzzjE/4PfLqfmaNGnijrf333/fxo4d65Z///33u2uG3qu/9VnpPBD9MJUOHTq4z1ifiZara432z6ZNm6LWk2d5yHOmTp2qq7/3/vvve7t27fI2b97szZw50zvrrLO8IkWKeFu2bHHzdevWzc33+OOPR73/v//9r5v+yiuvRE2fO3du1PSdO3d6BQsW9G644QbvxIkTkfmeeOIJN5+W71u4cKGbpv/l2LFjXrVq1bwqVap4P/30U9R6gsvq3bu3e1+srChjPBs3bnTzBfebfPLJJ276I488EpnWsmVLr27dut5vv/0WtS3NmjXzatSoEZn28MMPu/dqGT6Vs2TJkm661ilz5sxxzz/99FMvrbRf9d4PP/wwah2FChXy+vfvH5k2bNgwr1ixYt53330X9X4dEwUKFPA2bdqUZfs77Lrfeust997Ro0dH5tHx07x5czddx3uYz/CZZ56Jmp6UlOSmd+7cOWr6qlWr3PR77rknavqAAQPc9A8++CDZfl6yZElk2rx58yLHzA8//BCZ/pe//CXqHEjJ4MGD3Xxvvvlmstf8feqf4/6xktJ5Ji1atHDTJk+eHHe/lChRwn1uQWGPZb8crVq1ivq8dV7oM9y3b19k2kUXXeTKEpaWm9JjxowZkfl0TOk4Ssnnn3+e7FyNx78e9u3bN2qbdSzrmNa11Hfo0KGo9x45csSrU6eOd80110RNV7niXWNiP7+ff/7ZK1WqlNerV6+o+bZv3+6uC8HpfjmfeuqpqHkvvvhir2HDhpHnKq/m03EepOttvPMB/4emujysVatW7peHmkH0S1O/9vRrWb8ig/SrJEjV2moSUWKmfu35D9VUaBkLFy508+lXjn5t6VdLsAlNTS+p0S8o1Vho3tjck+CyUnIqyhikX9rB/aZfkfq1p+R12bt3r33wwQeuRkE1U3559EtfvwzVHV41K6L36BetluHT5+Q3k/r8/aJfsUePHrW0ql27tqu5CK6jZs2arikiuB81j2oLgvtRx45+1X744YdZtr/Drlv7SzksweNU+SFaR2YI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33/f6tWrF5nuv0/LUK+64DIbNGgQd1mFChVyDwAAgGxb41SwYEFr2LChLViwIDJNyeF63rRp0xTfp15zw4YNs7lz51qjRo2iXlMvOgVPwWUqZ+mTTz456TIBAACy/XAEGoqgW7duLgBq3LixG47gl19+sR49erjX1VNOwwwoD0k0/IDGaHr11Vfd2E9+3tIZZ5zhHrqz8cMPP2zDhw+3GjVqRIYjUB5U+/btE7qtAAAgZ0t44NSxY0fbtWuXC4YUBKk5TTVJfnL3pk2bXE8736RJk1xvvN/97ndRy0lKSrIhQ4a4vx977DEXfN177722b98+u+KKK9wyGcMJAADk6HGcsiPGcUJOwzhOAJAHxnECAADISQicAAAAckqOE5DX0KwGADkXNU4AAAAhETgBAACEROAEAAAQEoETAABASAROAAAAIRE4AQAAhETgBAAAEBKBEwAAQEgETgAAACEROAEAAIRE4AQAABASgRMAAEBIBE4AAAAhETgBAACEROAEAAAQEoETAABASAROAAAAIZ0WdkYAecu1t/XO8DLmz56YKWUBgOyCGicAAICQCJwAAABCInACAAAIicAJAAAgJAInAACAkAicAAAAQiJwAgAACInACQAAICQCJwAAgJAInAAAAEIicAIAAMgpgdPEiROtatWqVrhwYWvSpIktX748xXm//vpr69Chg5s/X758Nm7cuGTzDBkyxL0WfNSqVSuLtwIAAOQFCQ2cZs2aZf369bOkpCRbuXKl1a9f39q0aWM7d+6MO/+hQ4esevXqNnLkSCtfvnyKy73ooots27ZtkcdHH32UhVsBAADyioQGTs8++6z16tXLevToYbVr17bJkydb0aJF7aWXXoo7/6WXXmrPPPOMderUyQoVKpTick877TQXWPmPMmXKZOFWAACAvCJhgdORI0dsxYoV1qpVq/8rTP787vnSpUsztOx169ZZxYoVXe1Uly5dbNOmTSed//Dhw3bgwIGoBwAAQLYJnHbv3m3Hjx+3cuXKRU3X8+3bt6d7ucqTmjZtms2dO9cmTZpkGzdutObNm9vPP/+c4ntGjBhhJUuWjDzOOeecdK8fAADkXglPDs9sbdu2tdtuu83q1avn8qXeffdd27dvn7322mspvmfgwIG2f//+yGPz5s2ntMwAACBnOC1RK1beUYECBWzHjh1R0/X8ZInfaVWqVCm74IILbP369SnOo3ypk+VMAQAApLvGaeHChRneewULFrSGDRvaggULItNOnDjhnjdt2jTTPp2DBw/ahg0brEKFCpm2TAAAkDelK3C67rrr7LzzzrPhw4dnqFlLQxFMmTLFpk+fbmvWrLH777/ffvnlF9fLTrp27eqa0YIJ5atWrXIP/f3jjz+6v4O1SQMGDLDFixfb999/b0uWLLFbbrnF1Wx17tw53eUEAABId+CkgKVPnz72+uuvu55ryiVSDpGCmbTo2LGjjRkzxgYPHmwNGjRwQZCSuv2EcfWG0zhMvq1bt9rFF1/sHpqu9+rve+65JzLPli1bXJBUs2ZNu/322+2ss86yZcuW2dlnn80nDgAAMiSf53leRhaggSunTp1qM2bMcM/vuOMO69mzpxvMMqfScATqXadE8RIlSiS6OMhlrr2td4aXMX/2xBy5TADI6d/7Ge5Vd8kll7jmNNVAKZ9Ig1cqd0lDAOgWKQAAALlFugOno0ePuqa666+/3qpUqWLz5s2zCRMmuF5xyjnSNA0LAAAAkKeHI+jbt69rmlMr31133WWjR4+2OnXqRF4vVqyYyz/S6N0AAAB5OnD65ptv7Pnnn7dbb701xfGPNE5TZgxbAAAAkKOb6pKSklwzXGzQdOzYMfvwww8jN9pt0aJF5pQSAAAgpwZOV199te3duzfZdGWj6zUAAIDcKF1NdcptypcvX7Lpe/bscflNQG5Bl3wAQLoDJ+U0iYKm7t27RzXVHT9+3FavXm3NmjVLyyIBAAByZ+CkwaH8GqfixYtbkSJFou49d9lll1mvXr0yv5QAAAA5LXDSCOFStWpVd084muUAAEBeclp6e9UBAADkNael5dYqCxYssNKlS7sb68ZLDg/evw4AACDPBk7t2rWLJIO3b98+K8sEAACQswOnYPMcTXUAACAvSvdNfgEAAPKa0DVOym06WV5TULxRxQEAAPJM4DRu3LisLQkAAEBuCZy6deuWtSUBAADILYHTgQMHrESJEpG/T8afDwAAIM/mOG3bts3Kli1rpUqVipvv5N/8V/etAwAAyLOB0wcffGBnnnmm+3vhwoVZWSYAAICcHTi1aNEi7t8AAAB5RbruVSc//fST/e1vf7M1a9a457Vr17YePXpEaqUAAABym3QNgPnhhx9a1apVbfz48S6A0kN/V6tWzb0GAACQG6Wrxql3797WsWNHmzRpkhUoUMBNU0L4Aw884F778ssvM7ucAAAAObPGaf369da/f/9I0CT6u1+/fu41AACA3ChdgdMll1wSyW0K0rT69etnRrkAAAByblPd6tWrI38/+OCD9tBDD7napcsuu8xNW7ZsmU2cONFGjhyZNSUFAADIKYFTgwYN3OCWGuTS99hjjyWb74477nD5TwAQz7W39c7wMubPnpgpZQGALAucNm7cmOaFAwAA5MnAqUqVKllbEgAAgNw6AKZ88803tmnTJjty5EjU9Jtvvjmj5QIAAMgdver+97//ud5zderUsRtuuMHat2/vHrfccot7pIUSyjWYZuHCha1Jkya2fPnyFOf9+uuvrUOHDm5+5VuNGzcuw8sEAADI0sBJPeo0SvjOnTutaNGiLqDRiOGNGjWyRYsWhV7OrFmz3NhPSUlJtnLlSheMtWnTxi03nkOHDln16tVdz73y5ctnyjIBAACyNHBaunSpPfXUU1amTBnLnz+/e1xxxRU2YsQIN1RBWM8++6z16tXL3eNO97qbPHmyC8ReeumluPNfeuml9swzz1inTp2sUKFCmbJMAACALA2cdHuV4sWLu78VPG3dujWSQP7tt9+GWobyolasWGGtWrX6v8Lkz++eKzBLj/Qu8/Dhw3bgwIGoBwAAQKYETspt+uKLL9zfyiEaPXq0ffzxx64WSk1pYezevdsFYOXKlYuarufbt29PT7HSvUzVlJUsWTLyOOecc9K1fgAAkLulK3B68skn7cSJE+5vBUsa46l58+b27rvv2vjx4y2nGThwoO3fvz/y2Lx5c6KLBAAAcstwBEq29p1//vm2du1a27t3r5UuXdr1dgtDTXy6MfCOHTuiput5SonfWbVM5UullDMFAACQoRqnINXO6HHmmWeGDpqkYMGC1rBhQ1uwYEFkmmqx9Lxp06bpKktWLBMAACBDgdOxY8ds0KBBLh9I4yXpob/VhHf06NHQy9GwAVOmTLHp06fbmjVr7P7777dffvnF9YiTrl27uma0YPL3qlWr3EN///jjj+5v3Ww47DIBAABOaVNd37597c0333RJ4X5NjnqtDRkyxPbs2WOTJk0KtRzdDHjXrl02ePBgl7ytGwnPnTs3ktytUcnVK86n3nsXX3xx5PmYMWPco0WLFpHxo1JbJgAAwCkNnF599VWbOXOmtW3bNjKtXr16rjda586dQwdO0qdPH/eIJ3YwTdVseZ6XoWUCAACc0qY6JVIriIml0cSVZwQAAJAbpStwUm3OsGHD3MCRPv399NNPU9MDAAByrdBNdbfeemvU8/fff98qV67s7gUnGhBTCdstW7bM/FICAADkpMBJveaCOnToEPWc0bYBAEBuFzpwmjp1ataWBAAAIDf2qvOp279/U9+aNWva2WefnVnlAgAAyB3J4RpQ8u6777YKFSrYlVde6R4VK1a0nj172qFDhzK/lAAAADk1cNLo3IsXL7Z//etftm/fPvd4++233bT+/ftnfikBAAByalPdG2+8Ya+//rpdddVVkWnXX3+9FSlSxG6//fY0DYAJAACQq2uc1BwX7xYmZcuWpakOAADkWukKnHR/uqSkJPvtt98i03799VcbOnRo5N51AAAAuU26murGjRtn1113XbIBMAsXLmzz5s3L7DICAADk3MCpbt26tm7dOnvllVds7dq1bppu7tulSxeX5wQAAJAbpTlwOnr0qNWqVcveeecd69WrV9aUCgAAIDfkOJ1++ulRuU0AAAB5RbqSw3v37m2jRo2yY8eOZX6JAAAAclOO06effmoLFiyw9957z+U7FStWLOr1N998M7PKBwAAkLMDp1KlSlmHDh0yvzQAAAC5JXA6ceKEPfPMM/bdd9/ZkSNH7JprrrEhQ4bQkw4Jd+1tvTO8jPmzJ2ZKWQAAuVeacpyefvppe+KJJ+yMM86wSpUq2fjx412+EwAAQF6QpsDp5ZdfthdeeMENcvnWW2+5m/xqLCfVRAEAAOR2aQqcNm3a5G7m62vVqpXly5fPtm7dmhVlAwAAyLmBk4Yf0G1VYsd10qCYAAAAuV2aksM9z7Pu3btboUKFItM0GOZ9990XNSQBwxEAAADL64FTt27dkk278847M7M8AAAAuSNwmjp1ataVBAAAIDfecgUAACAvInACAAAIicAJAAAgJAInAACAkAicAAAAsqJXXVaZOHGiu3nw9u3brX79+vb8889b48aNU5x/9uzZNmjQIPv++++tRo0aNmrUqKgRzTXW1PTp06Pe06ZNG5s7d26WbgeAxOAmzwDyTI3TrFmzrF+/fpaUlGQrV650gZOCnJ07d8adf8mSJda5c2fr2bOnff7559a+fXv3+Oqrr6Lmu+6662zbtm2Rx4wZM07RFgEAgNwq4YHTs88+a7169bIePXpY7dq1bfLkyVa0aFF76aWX4s7/3HPPuaDo0UcftQsvvNCGDRtml1xyiU2YMCFqPo1uXr58+cijdOnSp2iLAABAbpXQwOnIkSO2YsUKd7PgSIHy53fPly5dGvc9mh6cX1RDFTv/okWLrGzZslazZk27//77bc+ePVm0FQAAIK9IaI7T7t277fjx41auXLmo6Xq+du3auO9RHlS8+TXdpxqpW2+91apVq2YbNmywJ554wtq2beuCqwIFCiRb5uHDh93Dd+DAgUzYOgAAkNtki+TwzNapU6fI33Xr1rV69erZeeed52qhWrZsmWz+ESNG2NChQ09xKQEAQE6T0Ka6MmXKuBqgHTt2RE3Xc+UlxaPpaZlfqlev7ta1fv36uK8PHDjQ9u/fH3ls3rw5XdsDAAByt4QGTgULFrSGDRvaggULItNOnDjhnjdt2jTuezQ9OL/Mnz8/xflly5YtLsepQoUKcV9XInmJEiWiHgAAANmuV52GIpgyZYobd2nNmjUukfuXX35xveyka9eurkbI99BDD7nxmMaOHevyoIYMGWKfffaZ9enTx71+8OBB1+Nu2bJlbpwnBVnt2rWz888/3yWRAwAA5Ngcp44dO9quXbts8ODBLsG7QYMGLjDyE8A3bdrketr5mjVrZq+++qo9+eSTLulbA2C+9dZbVqdOHfe6mv5Wr17tArF9+/ZZxYoVrXXr1m7YAtUsAQAA5NjASVRb5NcYxVJCd6zbbrvNPeIpUqSIzZs3L9PLCAAAkPCmOgAAgJyCwAkAACAkAicAAICQCJwAAABCInACAAAIicAJAAAgJAInAACAkAicAAAAQiJwAgAACInACQAAICQCJwAAgJAInAAAAEIicAIAAAiJwAkAACCk08LOCGSWa2/rneFlzJ89MVPKAgBAWlDjBAAAEBKBEwAAQEgETgAAACGR4wQAcZCLByAeapwAAABCInACAAAIicAJAAAgJAInAACAkAicAAAAQiJwAgAACInACQAAICQCJwAAgJAInAAAAEIicAIAAAiJwAkAACAkAicAAICQuMkvToobnQKZh/MJyPmyRY3TxIkTrWrVqla4cGFr0qSJLV++/KTzz54922rVquXmr1u3rr377rtRr3ueZ4MHD7YKFSpYkSJFrFWrVrZu3bos3goAAJDbJTxwmjVrlvXr18+SkpJs5cqVVr9+fWvTpo3t3Lkz7vxLliyxzp07W8+ePe3zzz+39u3bu8dXX30VmWf06NE2fvx4mzx5sn3yySdWrFgxt8zffvvtFG4ZAADIbRIeOD377LPWq1cv69Gjh9WuXdsFO0WLFrWXXnop7vzPPfecXXfddfboo4/ahRdeaMOGDbNLLrnEJkyYEKltGjdunD355JPWrl07q1evnr388su2detWe+utt07x1gEAgNwkoTlOR44csRUrVtjAgQMj0/Lnz++a1pYuXRr3PZquGqog1Sb5QdHGjRtt+/btbhm+kiVLuiZAvbdTp05Ztj0AkAjkTgF5JHDavXu3HT9+3MqVKxc1Xc/Xrl0b9z0KiuLNr+n+6/60lOaJdfjwYffw7d+/3/1/4MAByynade2f4WW8/fLYZNOOHT2S4eXG7secssysWm5eXmZWLTcvLzOrlptV1xQgO/KPf7VapYZedWY2YsQIGzp0aLLp55xzjuUlJUu+mGOWm1OWmVXLzcvLzKrl5uVl5rSyAlnl559/dq1U2TZwKlOmjBUoUMB27NgRNV3Py5cvH/c9mn6y+f3/NU296oLzNGjQIO4y1VQYbP47ceKE7d2718466yzLly+fJSLyVdC2efNmK1GixClfP8Lhc8oZ+JxyDj6rnOFALvycVNOkoKlixYqpzpvQwKlgwYLWsGFDW7BggesZ5wctet6nT5+472natKl7/eGHH45Mmz9/vpsu1apVc8GT5vEDJX3I6l13//33x11moUKF3COoVKlSlmg6IHPLQZmb8TnlDHxOOQefVc5QIpd9TqnVNGWbpjrV9HTr1s0aNWpkjRs3dj3ifvnlF9fLTrp27WqVKlVyzWny0EMPWYsWLWzs2LF2ww032MyZM+2zzz6zv/71r+511RApqBo+fLjVqFHDBVKDBg1yUaQfnAEAAKRHwgOnjh072q5du9yAlUreVi3R3LlzI8ndmzZtcj3tfM2aNbNXX33VDTfwxBNPuOBIPerq1KkTmeexxx5zwde9995r+/btsyuuuMItUwNmAgAApFc+L0wKOU4p9fBTDZtyr2KbEJF98DnlDHxOOQefVc5wOI9/TgROAAAAOWXkcAAAgJyCwAkAACAkAicAAICQCJyymYkTJ1rVqlVdD0DdX2/58uWJLhJiDBkyxA17EXzUqlUr0cXK8z788EO76aab3NAj+kxib+qtdE713tXAuEWKFHH3s1y3bl3CyptXpfY5de/ePdn5pRu749RS8vell15qxYsXt7Jly7rhfL799tuoeX777Tfr3bu3Gyz6jDPOsA4dOiQboDo3InDKRmbNmuXGtUpKSrKVK1da/fr13Q2Md+7cmeiiIcZFF11k27Ztizw++uijRBcpz9MQJDpn9OMjntGjR9v48eNt8uTJbkDcYsWKufNLF39kn89JFCgFz68ZM2ac0jLCbPHixS4oWrZsmRtk+ujRo9a6dWv3+fkeeeQR+9e//mWzZ89282/dutVuvfVWy/XUqw7ZQ+PGjb3evXtHnh8/ftyrWLGiN2LEiISWC9GSkpK8+vXrJ7oYOAld2ubMmRN5fuLECa98+fLeM888E5m2b98+r1ChQt6MGTMSVErEfk7SrVs3r127dgkrE+LbuXOn+7wWL14cOX9OP/10b/bs2ZF51qxZ4+ZZunSpl5tR45RNHDlyxFasWOGaD3wa+FPPly5dmtCyITk18aipoXr16talSxc3UCuyr40bN7oBdoPnl26voOZwzq/sZ9GiRa55qGbNmu5WWXv27El0kfK8/fv3u//PPPNM97++r1QLFTynlLJw7rnn5vpzisApm9i9e7cdP348MmK6T891wUf2oS/badOmudHoJ02a5L6Umzdv7m4QiezJP4c4v7I/NdO9/PLL7n6jo0aNck1Abdu2dddHJIbuIatbmV1++eWRu3TovNH9ZmPv65oXzqmE33IFyGl0EffVq1fPBVJVqlSx1157zXr27JnQsgE5XadOnSJ/161b151j5513nquFatmyZULLllcp1+mrr74il/P/ocYpmyhTpowVKFAgWY8EPS9fvnzCyoXU6RfXBRdcYOvXr090UZAC/xzi/Mp51Byu6yPnV2L06dPH3nnnHVu4cKFVrlw5Ml3njVJMdD/YvHZOEThlE6rybNiwoaueDlaP6nnTpk0TWjac3MGDB23Dhg2umzuyp2rVqrmLefD8OnDggOtdx/mVvW3ZssXlOHF+nVrK3VfQNGfOHPvggw/cORTUsGFDO/3006POKQ1XoHzP3H5O0VSXjWgogm7dulmjRo2scePGNm7cONf1s0ePHokuGgIGDBjgxqFR85y632r4CNUWdu7cOdFFs7wewAZrJZR7tmrVKpfMqoRV5WgMHz7catSo4b4EBg0a5BL8NT4NssfnpMfQoUPdeEAKdPWD5LHHHrPzzz/fDR2BU9s89+qrr9rbb7/txnLy85ZKlizpxkHT/0pN0PeWPrcSJUpY3759XdB02WWXWa6W6G59iPb888975557rlewYEE3PMGyZcsSXSTE6Nixo1ehQgX3GVWqVMk9X79+faKLlectXLjQdYWOfah7uz8kwaBBg7xy5cq5YQhatmzpffvtt4kudp5zss/p0KFDXuvWrb2zzz7bdXWvUqWK16tXL2/79u2JLnaeE+8z0mPq1KmReX799VfvgQce8EqXLu0VLVrUu+WWW7xt27Z5uV0+/ZPo4A0AACAnIMcJAAAgJAInAACAkAicAAAAQiJwAgAACInACQAAICQCJwAAgJAInAAAAEIicAIAAAiJwAlAjvP9999bvnz53K06sou1a9e6W00ULlzYGjRoEHeeq666yt36JbNNmzbN3WwaQNYjcAKQZt27d3eBy8iRI6Omv/XWW256XqR7FhYrVszd6DR441MAuQuBE4B0Uc3KqFGj7KeffrLc4siRI+l+r25Ie8UVV7ibP5911lmZWi4A2QeBE4B0adWqlbuD/YgRI1KcZ8iQIcmarcaNG2dVq1aNqr1q3769/elPf7Jy5cq5JqennnrKjh07Zo8++qi783rlypVt6tSpcZvHmjVr5oK4OnXq2OLFi6Ne/+qrr6xt27Z2xhlnuGXfddddtnv37qimsz59+rjmszJlylibNm3ibseJEydcmVSOQoUKuW2aO3du5HXVsq1YscLNo7+13SnRdmmduru81jlo0CDdbD3y+uHDh23AgAFWqVIlV4PVpEkTW7RoUbKmuXPPPdeKFi1qt9xyi+3Zsyfq9S+++MKuvvpqd1d73bW+YcOG9tlnn6VYJgDhETgBSJcCBQq4YOf555+3LVu2ZGhZH3zwgW3dutU+/PBDe/bZZ12z14033milS5e2Tz75xO677z77/e9/n2w9Cqz69+9vn3/+uTVt2tRuuummSBCxb98+u+aaa+ziiy92QYMCnR07dtjtt98etYzp06dbwYIF7eOPP7bJkyfHLd9zzz1nY8eOtTFjxtjq1atdgHXzzTfbunXr3Ovbtm2ziy66yJVFfyvwSYnWd9ppp9ny5cvdcrW9L774YuR1BVVLly61mTNnunXddtttdt1110XWpf3Rs2dPN59yvBQgDR8+PGodXbp0cUHep59+6gK6xx9/3E4//fQ0fy4A4vAAII26devmtWvXzv192WWXeXfffbf7e86cOao6icyXlJTk1a9fP+q9f/7zn70qVapELUvPjx8/HplWs2ZNr3nz5pHnx44d84oVK+bNmDHDPd+4caNbz8iRIyPzHD161KtcubI3atQo93zYsGFe69ato9a9efNm975vv/3WPW/RooV38cUXp7q9FStW9J5++umoaZdeeqn3wAMPRJ5rO7W9J6P1XXjhhd6JEyci0/7whz+4afLDDz94BQoU8H788ceo97Vs2dIbOHCg+7tz587e9ddfH/V6x44dvZIlS0aeFy9e3Js2bVqq2wUg7ahxApAhynNSLcqaNWvSvQzV1uTP/3+XIzWr1a1bN6p2S3lDO3fujHqfapl8qsVp1KhRpBxqrlq4cKFrpvMftWrViuQj+dSMdTIHDhxwtWGXX3551HQ9T882q+ddMIFe26DapOPHj9uXX37p/r/ggguiyq0mSL/MWqea71LaD9KvXz+75557XHOqEviD2wsgY07L4PsB5HFXXnmla7oaOHCgy1cKUjAUzN+Ro0ePJltGbDOSAot405RrFNbBgwdd050Cu1gVKlSI/K08ouxCZVaQqOY1/R+kACos5Vjdcccd9u9//9v+85//uKZPNf0pHwpAxhA4Acgw1WooYbpmzZpR088++2zbvn27C578WpbMHHtp2bJlLnDzk64VcCj3Ry655BJ74403XCK6aqPSS8nVFStWdDlQLVq0iEzX88aNG6d5ecpRit2GGjVquEBJ+ViqcVLNWvPmzeO+/8ILL4y7jFiqtdLjkUcesc6dO7vkegInIONoqgOQYWpWU0Ly+PHjo6ar19quXbts9OjRrrlo4sSJrgYks2h5c+bMcb3revfu7YZGuPvuu91rer53714XNChJWuufN2+e9ejRwwUnaaEkdNVczZo1y43TpGRrBYAPPfRQmsu8adMm15Sm5cyYMcMl1/vLUaCj/di1a1d78803bePGjS6JXD0XVXskDz74oEt0V6K6mvgmTJgQ1cPv119/dcGjeuL98MMPLsDT9ivgApBxBE4AMoW64sc2penL+oUXXnABTv369V0QcLIeZ+mp6dJDy/7oo4/sn//8p+viL34tkYKk1q1bu+BOww5ouINgPlUYClYU7KjXnJajQEXrUk1RWikoUnCj2ioFdwqa7r333sjrqhnSPFqXavA0VIMCHw0/4OdITZkyxfXI03a/99579uSTT0ber5or9SzUMhSIqRehhmQYOnRomssKILl8yhCPMx0AAAAxqHECAAAIicAJAAAgJAInAACAkAicAAAAQiJwAgAACInACQAAICQCJwAAgJAInAAAAEIicAIAAAiJwAkAACAkAicAAICQCJwAAAAsnP8P8GN1HUU6zDwAAAAASUVORK5CYII=", - "text/plain": [ - "
" + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Step 3: Wrap a Poisson rate in a `FlowInputs` container\n", + "\n", + "In notebook 3e, we used Poisson distributions to model yet-to-arrive patients. The yet-to-arrive model's `predict()` method returns a full probability distribution — a DataFrame with an `agg_proba` column, just like the bed count distributions from notebook 3a.\n", + "\n", + "Let's call `predict()` on the model we just trained to see the result." ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "title = (\n", - " f'Predicted beds needed from current ED patients\\n'\n", - " f'at {format_prediction_time(prediction_time)} '\n", - " f'on {snapshot_date}'\n", - ")\n", - "plot_prob_dist(arrivals.probabilities, title, include_titles=True)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "This is the same distribution as Step 1 — the `DemandPredictor` simply passes through the PMF when there is only one flow selected. The value is in what it provides: summary statistics (expectation, mode, percentiles) and the ability to combine multiple flows, as we'll see next." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Step 6: Use `FlowSelection` to control which flows are included\n", - "\n", - "The `FlowSelection` class is a toggle for which flows to include in a prediction. It provides several presets and a `custom()` method for full control.\n", - "\n", - "Let's combine current ED patients with yet-to-arrive patients. This is where convolution happens — the `DemandPredictor` convolves the PMF from current patients with the Poisson distribution from yet-to-arrive patients to produce a single combined distribution." - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": { - "execution": { - "iopub.execute_input": "2026-02-23T08:42:53.242705Z", - "iopub.status.busy": "2026-02-23T08:42:53.242573Z", - "iopub.status.idle": "2026-02-23T08:42:53.257443Z", - "shell.execute_reply": "2026-02-23T08:42:53.257053Z" - } - }, - "outputs": [ + }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "Current ED only — expected beds: 6.9\n", - "Yet-to-arrive only — Poisson rate: 18.6\n", - "Combined — expected beds: 25.5\n" - ] - } - ], - "source": [ - "# Include both current ED and yet-to-arrive patients\n", - "combined_bundle = predictor.predict_service(\n", - " inputs=service_inputs,\n", - " flow_selection=FlowSelection.custom(\n", - " include_ed_current=True,\n", - " include_ed_yta=True,\n", - " include_non_ed_yta=False,\n", - " include_elective_yta=False,\n", - " include_transfers_in=False,\n", - " include_departures=False,\n", - " cohort='emergency'\n", - " )\n", - ")\n", - "\n", - "print(f'Current ED only — expected beds: {current_ed_bundle.arrivals.expectation:.1f}')\n", - "print(f'Yet-to-arrive only — Poisson rate: {yta_lambda:.1f}')\n", - "print(f'Combined — expected beds: {combined_bundle.arrivals.expectation:.1f}')\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The expected value of the combined distribution equals the sum of the individual expected values — a property of convolution. But the full probability distribution captures the combined uncertainty, not just the means." - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": { - "execution": { - "iopub.execute_input": "2026-02-23T08:42:53.258681Z", - "iopub.status.busy": "2026-02-23T08:42:53.258601Z", - "iopub.status.idle": "2026-02-23T08:42:53.338724Z", - "shell.execute_reply": "2026-02-23T08:42:53.338349Z" - } - }, - "outputs": [ + "cell_type": "code", + "execution_count": 32, + "metadata": { + "execution": { + "iopub.execute_input": "2026-02-23T08:42:53.016460Z", + "iopub.status.busy": "2026-02-23T08:42:53.016355Z", + "iopub.status.idle": "2026-02-23T08:42:53.035498Z", + "shell.execute_reply": "2026-02-23T08:42:53.035054Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Yet-to-arrive distribution (first 10 rows):\n" + ] + }, + { + "data": { + "text/html": [ + "
\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", + "
agg_proba
sum
08.208667e-09
11.528296e-07
21.422696e-06
38.829289e-06
44.109609e-05
51.530260e-04
64.748417e-04
71.262948e-03
82.939208e-03
96.080267e-03
\n", + "
" + ], + "text/plain": [ + " agg_proba\n", + "sum \n", + "0 8.208667e-09\n", + "1 1.528296e-07\n", + "2 1.422696e-06\n", + "3 8.829289e-06\n", + "4 4.109609e-05\n", + "5 1.530260e-04\n", + "6 4.748417e-04\n", + "7 1.262948e-03\n", + "8 2.939208e-03\n", + "9 6.080267e-03" + ] + }, + "execution_count": 32, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "prediction_context = {'unfiltered': {'prediction_time': prediction_time}}\n", + "\n", + "# predict() returns a full probability distribution\n", + "yta_prediction = yta_model.predict(prediction_context, x1=x1, y1=y1, x2=x2, y2=y2, max_value=50)\n", + "yta_distribution = yta_prediction['unfiltered']\n", + "\n", + "print('Yet-to-arrive distribution (first 10 rows):')\n", + "yta_distribution.head(10)" + ] + }, { - "data": { - "image/png": "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", - "text/plain": [ - "
" + "cell_type": "code", + "execution_count": 33, + "metadata": { + "execution": { + "iopub.execute_input": "2026-02-23T08:42:53.036791Z", + "iopub.status.busy": "2026-02-23T08:42:53.036699Z", + "iopub.status.idle": "2026-02-23T08:42:53.104101Z", + "shell.execute_reply": "2026-02-23T08:42:53.103630Z" + } + }, + "outputs": [ + { + "data": { + "image/png": "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wcPBoEkjQ8MSyX0aJ8DTAW7bts126A46rC1btthTxB0ITnRynTt3tnnLSehjx441q1atsvmUnuBB40bI5be8h0GMZSz+X7p0qe0seD4dBfHl+QwKdH5o1e655x47oHPCur9TpJwZWBj0+T1CAnVnwIABZuvWrVZwija/Eg15GnqSO2WI8Dpo0KDAAMTJ72jJGPD9MPOkvMlfB3+ff/75QUIXMLi45UIEpEhMnz7d5hnOZWkbxIcT4X/99Vf7nR8GTuodkxqEUJYsGWAZpPk9UK9atmxp60v37t2tNm7GjBm2fcYC5YvQT74wgFJuGCpPmzYtEAb7OZ5LnBCWSQeOchk8yBdn00adom1Sl/r3728HPQRShMI333wz0AdQPpQFee/CUSejHVijqdMZMXToUBsO4QStLOlGk0k5unjMnz/fTi7p58gf+h7qMUIgfZEre+oRGkwGeuoW6SJ8qAARqe+j36Uc3UYf18/xv4N8xo4vkkkDE9LvvvvOTJkyxdo8uvpPnBy8A01Qjx49rGCGIHfzzTebjRs32jqZHtGMAeGgziIsU3+rVKliT6igf0Obi9Dn7+firafk/eDBg2050k5Y8qeesrEmo34yPThZgz6BCQ1CHX/zLuzAMAugHjB+YKu5cuVK87e//c1kKzEdiyxihlPdOcXbcdNNN9krT5483vvvv2/vrVy50p5g/fbbbwfCcYo29zip3LFjxw57cvf9998fuHfffffZcJ988knQaducdl6pUiXv2LFjEePGSfb8dvbs2fbz6tWr7WdO/a5fv34gHCfDc8J86Ank/hPnw53kHs1p6JzkfejQoaB7v/32m1eqVCl72rzDnQ5epEgRmw9+eAfftW/fPs3z3XcOTobn83PPPRcUrkePHt5pp53mHThwwH4mPwn32muvBYWbM2dO2PuhuOf4mTJlSpoyjXSaOyfQh55O705d58T57777Luh+//79bZ3auHFjhvkVbb0NLc/0IE2cxD5w4MCg+y59/npAWkPzwUHdK126dFA+XH311WnCrV271j5j/PjxMZfDsGHDbFx/+eWXoPrL8x5//PGgsNT7OnXqBD7PnDnThhsxYkRQHW7UqJG9P2nSpHTjw/eEa9q0qXf8+PHA/T59+tjy+/333wNtuFixYl63bt2Cfr9t2zavaNGiQfebNGni1ahRwzt48GDgHs9u2LCh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5rvvvrMe2YUQQgghsk0zxdKZ096kZ8wdCyytderUydStW9fUq1fPjB492uzfv9/u7oOOHTuasmXLWpsm6N27t12qGzlypGnRooWZOnWqWb58uZkwYULgmez0a9eunbniiiusm4Y5c+aYd99917pJEEIIIYTINmHKv7SXiGU+QOjZuXOnefTRR60ROfZNCD/OyBxHm+zwc7BTcPLkyeaRRx4xDz/8sKlcubLdyec/ygaDc+yjEMDuvfdeU6VKFfPmm29a31NCCCGEECeFzVQi6dWrl73CEU6bhOf1jA5Q7tKli72EEEIIIU4aYer0008P66gzHOG8owshsh8dviuEENkoTGHPJIQQQgghMilMYSguhBBCCCEyKUzhyLJIkSKBv9PDhRNCCCGESHVispnaunWrPTC4WLFiYe2n3AHIHBMjhBBCCJETiFqYmj9/vilevLj9e8GCBVkZJyGEEEKI1BOm/OfaRTrjTgghhBAip5FpP1McLfPSSy+Zb7/91n7mPDw8lzvtlRBCCCFETiDqs/n8fPzxx6ZSpUrm2WeftUIVF3+fffbZ9jshhBBCiJxCpjRTPXv2tEfBvPDCCyZPnjz2HkbnPXr0sN99/fXXiY6nEEIIIUTqCFM//PCDeeONNwKCFPA3Bxe/8soriYyfEELkCOSdXogctsxXu3btgK2UH+7VrFkzEfESQgghhEgtzdTq1asDf997772md+/eVkN16aWX2ntLly4148aNM8OHD8+amAohhBBCJLMwVatWLeuQE8ecjgcffDBNuNtuu83aUwkhhBBC5ASiFqY2bNiQtTERQgghhEhlYapixYpZGxMhhBBCiJzktBO++eYbs3HjRnP48OGg+zfeeGO88RJCCCGESF1h6qeffjKtW7e2/qT8dlTu8GMddCyEEEKInEKmXCOwkw9v5zt27DAFCxY0a9eutZ7P69ataxYuXJj4WAohhBBCpJJmasmSJWb+/PmmRIkSJnfu3Pa6/PLLzbBhw6zbhFWrViU+pkIIIYQQqaKZYhmvcOHC9m8Eqi1btgSM1NevX5/YGAohhBBCpJpmqnr16uarr76yS33169c3I0aMMPny5TMTJkww55xzTuJjKYQQQgiRSsLUI488Yvbv32//fvzxx831119vGjVqZM444wwzbdq0RMdRCCGEECK1hKnmzZsH/j7vvPPMunXrzJ49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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "title = (\n", + " f'Probability distribution for number of beds needed for patients\\n'\n", + " f'who will arrive after {format_prediction_time(prediction_time)} '\n", + " f'and need a bed within 8 hours'\n", + ")\n", + "plot_prob_dist(yta_distribution, title, include_titles=True, truncate_at_beds=40, bar_colour='green')" ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "title = (\n", - " f'Predicted beds needed from current ED and yet-to-arrive patients\\n'\n", - " f'at {format_prediction_time(prediction_time)} '\n", - " f'on {snapshot_date}'\n", - ")\n", - "plot_prob_dist(\n", - " combined_bundle.arrivals.probabilities, title,\n", - " include_titles=True,\n", - " probability_levels=[0.75, 0.25],\n", - " show_probability_thresholds=True,\n", - " bar_colour='orange'\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now let's compare two presets — `FlowSelection.incoming_only()` includes all inflows but no departures, while `FlowSelection.default()` includes everything." - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": { - "execution": { - "iopub.execute_input": "2026-02-23T08:42:53.340259Z", - "iopub.status.busy": "2026-02-23T08:42:53.340163Z", - "iopub.status.idle": "2026-02-23T08:42:53.356429Z", - "shell.execute_reply": "2026-02-23T08:42:53.355991Z" - } - }, - "outputs": [ + }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "=== FlowSelection.incoming_only() ===\n", - " Expected arrivals: 25.5\n", - " Expected departures: 0.0\n", - " Expected net flow: 25.5\n", - "\n", - "=== FlowSelection.default() ===\n", - " Expected arrivals: 25.5\n", - " Expected departures: 7.0\n", - " Expected net flow: 18.5\n" - ] - } - ], - "source": [ - "incoming_bundle = predictor.predict_service(\n", - " inputs=service_inputs,\n", - " flow_selection=FlowSelection.incoming_only()\n", - ")\n", - "\n", - "default_bundle = predictor.predict_service(\n", - " inputs=service_inputs,\n", - " flow_selection=FlowSelection.default()\n", - ")\n", - "\n", - "print('=== FlowSelection.incoming_only() ===')\n", - "print(f' Expected arrivals: {incoming_bundle.arrivals.expectation:.1f}')\n", - "print(f' Expected departures: {incoming_bundle.departures.expectation:.1f}')\n", - "print(f' Expected net flow: {incoming_bundle.net_flow.expectation:.1f}')\n", - "print()\n", - "print('=== FlowSelection.default() ===')\n", - "print(f' Expected arrivals: {default_bundle.arrivals.expectation:.1f}')\n", - "print(f' Expected departures: {default_bundle.departures.expectation:.1f}')\n", - "print(f' Expected net flow: {default_bundle.net_flow.expectation:.1f}')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The available presets are:\n", - "- `FlowSelection.default()` — all flows\n", - "- `FlowSelection.incoming_only()` — all inflows, no departures\n", - "- `FlowSelection.outgoing_only()` — only departures\n", - "- `FlowSelection.emergency_only()` — only emergency-related flows\n", - "- `FlowSelection.elective_only()` — only elective-related flows\n", - "- `FlowSelection.custom(...)` — full control over individual flow families" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Step 7: The `PredictionBundle` — arrivals, departures, and net flow\n", - "\n", - "Every call to `predictor.predict_service()` returns a `PredictionBundle`. This bundles together three `DemandPrediction` objects:\n", - "\n", - "- **arrivals** — the combined inflow distribution\n", - "- **departures** — the combined outflow distribution\n", - "- **net_flow** — the difference (arrivals minus departures)\n", - "\n", - "It also records which `FlowSelection` was used, so you can always trace what went into the prediction." - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": { - "execution": { - "iopub.execute_input": "2026-02-23T08:42:53.357774Z", - "iopub.status.busy": "2026-02-23T08:42:53.357687Z", - "iopub.status.idle": "2026-02-23T08:42:53.370932Z", - "shell.execute_reply": "2026-02-23T08:42:53.370607Z" - } - }, - "outputs": [ + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Because this distribution is based on a Poisson model, the `DemandPredictor` can regenerate it from just the Poisson mean (lambda). The model provides a `predict_mean()` method for this purpose. This is what `build_service_data()` uses internally in the 4x_ notebooks — it stores just the Poisson rate in the `FlowInputs` container, and the `DemandPredictor` reconstructs the full distribution when needed." + ] + }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "PredictionBundle(service: medical)\n", - " Arrivals: PMF[20:30]: [0.046, 0.057, 0.068, 0.077, 0.082, 0.085, 0.083, 0.078, 0.070, 0.061] (E=25.5)\n", - " Departures: PMF[0:1]: [1.000] (E=0.0)\n", - " Net flow: PMF[20:30]: [0.046, 0.057, 0.068, 0.077, 0.082, 0.085, 0.083, 0.078, 0.070, 0.061] (E=25.5)\n", - " Flows: selection cohort=emergency inflows(ed_current=True, ed_yta=True, non_ed_yta=False, elective_yta=False, transfers_in=False) outflows(departures=False)\n" - ] - } - ], - "source": [ - "print(combined_bundle)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Each `DemandPrediction` carries useful summary statistics:" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": { - "execution": { - "iopub.execute_input": "2026-02-23T08:42:53.372312Z", - "iopub.status.busy": "2026-02-23T08:42:53.372241Z", - "iopub.status.idle": "2026-02-23T08:42:53.385668Z", - "shell.execute_reply": "2026-02-23T08:42:53.385298Z" - } - }, - "outputs": [ + "cell_type": "code", + "execution_count": 34, + "metadata": { + "execution": { + "iopub.execute_input": "2026-02-23T08:42:53.105599Z", + "iopub.status.busy": "2026-02-23T08:42:53.105504Z", + "iopub.status.idle": "2026-02-23T08:42:53.119373Z", + "shell.execute_reply": "2026-02-23T08:42:53.118988Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Yet-to-arrive Poisson rate (lambda): 18.618\n" + ] + } + ], + "source": [ + "# predict_mean() returns just the Poisson rate (a single float)\n", + "yta_lambda = yta_model.predict_mean(prediction_context, x1=x1, y1=y1, x2=x2, y2=y2)\n", + "\n", + "print(f'Yet-to-arrive Poisson rate (lambda): {yta_lambda:.3f}')\n" + ] + }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "Expected beds: 25.5\n", - "Most likely (mode): 25\n", - "Percentiles: {25: 22, 50: 25, 75: 29}\n", - "90% probability: need at least 20 beds\n", - "PMF array length: 76\n" - ] - } - ], - "source": [ - "arrivals = combined_bundle.arrivals\n", - "\n", - "print(f'Expected beds: {arrivals.expectation:.1f}')\n", - "print(f'Most likely (mode): {arrivals.mode}')\n", - "print(f'Percentiles: {arrivals.percentiles}')\n", - "print(f'90% probability: need at least {arrivals.min_beds_with_probability(0.9)} beds')\n", - "print(f'PMF array length: {len(arrivals.probabilities)}')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "The `flow_selection` attribute records which flows were included:" - ] - }, - { - "cell_type": "code", - "execution_count": 21, - "metadata": { - "execution": { - "iopub.execute_input": "2026-02-23T08:42:53.387048Z", - "iopub.status.busy": "2026-02-23T08:42:53.386972Z", - "iopub.status.idle": "2026-02-23T08:42:53.400890Z", - "shell.execute_reply": "2026-02-23T08:42:53.400519Z" - } - }, - "outputs": [ + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We can wrap this Poisson rate in a `FlowInputs` container. The key difference from Step 2 is that `flow_type` is `\"poisson\"` and `distribution` is a float (the rate) rather than a numpy array." + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": { + "execution": { + "iopub.execute_input": "2026-02-23T08:42:53.120630Z", + "iopub.status.busy": "2026-02-23T08:42:53.120552Z", + "iopub.status.idle": "2026-02-23T08:42:53.134389Z", + "shell.execute_reply": "2026-02-23T08:42:53.134026Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Flow ID: ed_yta\n", + "Flow type: poisson\n", + "Display name: ED yet-to-arrive admissions\n", + "Distribution: 18.618075334578297 (Poisson lambda)\n" + ] + } + ], + "source": [ + "ed_yta_flow = FlowInputs(\n", + " flow_id=\"ed_yta\",\n", + " flow_type=\"poisson\",\n", + " distribution=yta_lambda,\n", + " display_name=\"ED yet-to-arrive admissions\"\n", + ")\n", + "\n", + "print(f'Flow ID: {ed_yta_flow.flow_id}')\n", + "print(f'Flow type: {ed_yta_flow.flow_type}')\n", + "print(f'Display name: {ed_yta_flow.get_display_name()}')\n", + "print(f'Distribution: {ed_yta_flow.distribution} (Poisson lambda)')\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Both PMF and Poisson flows use the same `FlowInputs` container, distinguished only by `flow_type`. This uniform interface means downstream code can handle any flow without special-casing.\n", + "\n", + "Because we used a `ParametricIncomingAdmissionPredictor` here, the Poisson rate reflects demand as if ED performance targets are met — an *aspirational* prediction. When `build_service_data()` constructs this flow automatically, it sets `aspirational=True` on the `ed_yta` `FlowInputs` so that downstream code can detect this. See notebook 4d for how this affects evaluation." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Step 4: Group flows into a `ServicePredictionInputs`\n", + "\n", + "A hospital service (e.g. \"medical\") has multiple sources of incoming patients and potentially outgoing patients too. `ServicePredictionInputs` groups all of these into a single object, organised as **inflows** and **outflows**.\n", + "\n", + "Let's build one using the two flows we just created. For the departure flows, we'll create simple fake PMFs from a Poisson distribution to represent expected discharges. For transfers and other inflows where we don't have models, we use zero placeholders — a PMF of `[1.0]` (certainly zero patients) or a Poisson rate of `0.0`." + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "metadata": { + "execution": { + "iopub.execute_input": "2026-02-23T08:42:53.136112Z", + "iopub.status.busy": "2026-02-23T08:42:53.136001Z", + "iopub.status.idle": "2026-02-23T08:42:53.151196Z", + "shell.execute_reply": "2026-02-23T08:42:53.150877Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ServicePredictionInputs(service='medical')\n", + " INFLOWS:\n", + " Admissions from current ED PMF[2:12]: [0.007, 0.026, 0.071, 0.135, 0.191, 0.204, 0.169, 0.109, 0.056, 0.022] (E=6.9 of 21 patients in ED)\n", + " ED yet-to-arrive admissions λ = 18.618\n", + " Non-ED emergency admissions λ = 0.000\n", + " Elective admissions λ = 0.000\n", + " Elective transfers from other services PMF[0:1]: [1.000] (E=0.0)\n", + " Emergency transfers from other services PMF[0:1]: [1.000] (E=0.0)\n", + " OUTFLOWS:\n", + " Emergency inpatient departures PMF[0:10]: [0.007, 0.034, 0.084, 0.140, 0.175, 0.175, 0.146, 0.104, 0.065, 0.036] (E=5.0 of 29 emergency patients in service)\n", + " Elective inpatient departures PMF[0:10]: [0.135, 0.271, 0.271, 0.180, 0.090, 0.036, 0.012, 0.003, 0.001, 0.000] (E=2.0 of 19 elective patients in service)\n" + ] + } + ], + "source": [ + "from patientflow.predict.service import ServicePredictionInputs\n", + "from scipy.stats import poisson as poisson_dist\n", + "\n", + "prediction_window = timedelta(hours=8)\n", + "\n", + "# Create fake departure PMFs from Poisson distributions\n", + "emergency_departure_pmf = poisson_dist.pmf(np.arange(30), mu=5) # ~5 emergency discharges expected\n", + "elective_departure_pmf = poisson_dist.pmf(np.arange(20), mu=2) # ~2 elective discharges expected\n", + "\n", + "service_inputs = ServicePredictionInputs(\n", + " service_id='medical',\n", + " prediction_window=prediction_window,\n", + " inflows={\n", + " 'ed_current': ed_current_flow,\n", + " 'ed_yta': ed_yta_flow,\n", + " 'non_ed_yta': FlowInputs(\n", + " flow_id='non_ed_yta', flow_type='poisson',\n", + " distribution=0.0, display_name='Non-ED emergency admissions',\n", + " ),\n", + " 'elective_yta': FlowInputs(\n", + " flow_id='elective_yta', flow_type='poisson',\n", + " distribution=0.0, display_name='Elective admissions',\n", + " ),\n", + " 'elective_transfers': FlowInputs(\n", + " flow_id='elective_transfers', flow_type='pmf',\n", + " distribution=np.array([1.0]),\n", + " display_name='Elective transfers from other services',\n", + " ),\n", + " 'emergency_transfers': FlowInputs(\n", + " flow_id='emergency_transfers', flow_type='pmf',\n", + " distribution=np.array([1.0]),\n", + " display_name='Emergency transfers from other services',\n", + " ),\n", + " },\n", + " outflows={\n", + " 'emergency_departures': FlowInputs(\n", + " flow_id='emergency_departures', flow_type='pmf',\n", + " distribution=emergency_departure_pmf,\n", + " display_name='Emergency inpatient departures',\n", + " ),\n", + " 'elective_departures': FlowInputs(\n", + " flow_id='elective_departures', flow_type='pmf',\n", + " distribution=elective_departure_pmf,\n", + " display_name='Elective inpatient departures',\n", + " ),\n", + " },\n", + ")\n", + "\n", + "print(service_inputs)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The printed representation shows all inflows and outflows at a glance. The `ed_current` flow shows the PMF from Step 1, and the `ed_yta` flow shows the Poisson rate from Step 3. The departure flows use fake Poisson PMFs (with expected values of ~5 and ~2 respectively), and the transfer flows are zero placeholders.\n", + "\n", + "In a production system, these departure distributions would come from discharge prediction models, and the transfer flows would also be populated. You'll see this in the 4x_ notebooks." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Step 5: Use `DemandPredictor` to generate a prediction\n", + "\n", + "The `DemandPredictor` takes a `ServicePredictionInputs` and convolves the selected flows into a combined probability distribution. This is the same convolution we performed manually in notebook 3e (where we convolved multiple Poisson distributions using `np.convolve`), but wrapped in a method that handles both PMF and Poisson flows automatically.\n", + "\n", + "Let's predict demand using only the current ED patients first." + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": { + "execution": { + "iopub.execute_input": "2026-02-23T08:42:53.152652Z", + "iopub.status.busy": "2026-02-23T08:42:53.152571Z", + "iopub.status.idle": "2026-02-23T08:42:53.170209Z", + "shell.execute_reply": "2026-02-23T08:42:53.169810Z" + } + }, + "outputs": [], + "source": [ + "from patientflow.predict.demand import DemandPredictor\n", + "from patientflow.predict.demand import FlowSelection\n", + "\n", + "predictor = DemandPredictor(k_sigma=8.0)\n", + "\n", + "# Predict using only the current ED patients\n", + "current_ed_bundle = predictor.predict_service(\n", + " inputs=service_inputs,\n", + " flow_selection=FlowSelection.custom(\n", + " include_ed_current=True,\n", + " include_ed_yta=False,\n", + " include_non_ed_yta=False,\n", + " include_elective_yta=False,\n", + " include_transfers_in=False,\n", + " include_departures=False,\n", + " cohort='emergency'\n", + " )\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The result is a `PredictionBundle` containing a `DemandPrediction` for arrivals. Let's look at the arrivals prediction — this corresponds to the PMF we started with." + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": { + "execution": { + "iopub.execute_input": "2026-02-23T08:42:53.171695Z", + "iopub.status.busy": "2026-02-23T08:42:53.171616Z", + "iopub.status.idle": "2026-02-23T08:42:53.186969Z", + "shell.execute_reply": "2026-02-23T08:42:53.186533Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Expectation: 6.9\n", + "Expected value: 7\n", + "Percentiles: {25: 6, 50: 7, 75: 8}\n", + "PMF shape: (22,)\n" + ] + } + ], + "source": [ + "arrivals = current_ed_bundle.arrivals\n", + "\n", + "print(f'Expectation: {arrivals.expectation:.1f}')\n", + "print(f'Expected value: {arrivals.mode}')\n", + "print(f'Percentiles: {arrivals.percentiles}')\n", + "print(f'PMF shape: {arrivals.probabilities.shape}')" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": { + "execution": { + "iopub.execute_input": "2026-02-23T08:42:53.188175Z", + "iopub.status.busy": "2026-02-23T08:42:53.188096Z", + "iopub.status.idle": "2026-02-23T08:42:53.241049Z", + "shell.execute_reply": "2026-02-23T08:42:53.240580Z" + } + }, + "outputs": [ + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAk4AAAEiCAYAAAAPh11JAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjMsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvZiW1igAAAAlwSFlzAAAPYQAAD2EBqD+naQAAP2RJREFUeJzt3QvcTWX+//8PyjGnknM5lEhORURJRaQTZQoph6Sp0AE1aeImGodoJGJGE5oppFIzTUMSmkKKpAOFUciZkJTj+j/e1/+39nftfe/bve6TfR9ez8djc++1117rWmuvtfZnX9fnulY+z/M8AwAAQKrypz4LAAAAhMAJAAAgJAInAACAkAicAAAAQiJwAgAACInACQAAICQCJwAAgJAInAAAAEIicAIAAAiJwAkJUbVqVevevXvk+aJFiyxfvnzu/+xaxni+//57V+4xY8ZkeXmmTZvm1qV15kZh9nda+J+N9ltq1q1bZ61bt7aSJUu697z11luZVg4grXL7uZ7TETjl4ZPSfxQuXNguuOAC69Onj+3YscNyknfffdeGDBmS6GIgh+vWrZt9+eWX9vTTT9vf//53a9SoUaKLlOe88MILoYJcX/AaFvu47777IvMpGA++dsYZZ1j16tXtd7/7nb3xxht24sQJS5Q//elPCQvSDx065K6d2enHak5xWqILgMR56qmnrFq1avbbb7/ZRx99ZJMmTXKByFdffWVFixY9pWW58sor7ddff7WCBQum6X0q78SJEwmekG467pYuXWp//OMf3Y8HJC5wKlOmTJpqHa+99lrr2rVrsun6IRhUqFAhe/HFFyOf9w8//GD/+te/XPB01VVX2dtvv20lSpSwRAROKkP79u2jpt91113WqVMnV+6sDJyGDh3q/tY+QHgETnlY27ZtI7+s77nnHjvrrLPs2WefdReRzp07x33PL7/8YsWKFcv0suTPn9/VfAGn2q5du9z/pUqVSnXerDr+sxt9qcb78XTs2DFXQ5PWHzhZRQHSnXfemep8p512WrL5hg8fbiNHjrSBAwdar169bNasWZZdFChQwD2QPdFUh4hrrrnG/b9x40b3v375qVp7w4YNdv3111vx4sWtS5cu7jVdPMeNG2cXXXSRC3jKlStnv//97+2nn36KWqbnee4CVblyZXchvvrqq+3rr79Otu6Ucpw++eQTt+7SpUu7L6x69erZc889FymfapskWBXvy+wypubPf/6zValSxYoUKWItWrRwNXex1q5d635hnnnmma5MClz/+c9/JptP69fnoWWpXCpfvCaFzz77zNq0aeN+qWte1SDefffdofKJbrzxRlfT2LhxY1cWNV+8/PLLyebdt2+fPfzww3bOOee4X8Dnn3++jRo1Kll5smJ/h1235tPxoBwlBUBqetO01KimUp+ZPProo+740b7xX9Pzb775xu644w53DF5xxRWRAGLYsGF23nnnuXLpPU888YQdPnw47n7Wca3PWp9R3bp1I8f5m2++6Z5rfzVs2NA+//zzVMvsb+8jjzzilq/1a1+q5mX37t0nzZGJd56ptqFOnTq2YsUKV/Orz0TbEszf0+fqb6v2R9hj2S/Hxx9/bP369bOzzz7bnce33HJLJGD195OOgcWLF0fO41NRC/L444+73LbZs2fbd999d9J5/evh//73P3fOaTsqVqzoau51TAdpnzVr1sz9GNVnrs/29ddfj5pH26hAfPr06ZFt9mvbUvr8/vOf/1jz5s3dunU9vuGGG5KdO345f/zxR1eTpb+13wcMGGDHjx9382i5miaqdfLX79fcb9++3Xr06OGOK33mFSpUsHbt2pFz9f9Q44QIBUiik92nLwhdJPSFoYuB/ytUX4g6uXVyPfjggy7YmjBhgrvw6yJ5+umnu/kGDx7sviQV/OixcuVKd6E6cuRIquWZP3+++9LRSfvQQw9Z+fLlbc2aNfbOO++45yrD1q1b3XzKS4l1KsroU8Dx888/W+/evV3Tp4I7BT7Km1EAIbrAXX755VapUiV3wdbF77XXXnMXN+Va6MvEv2gpmNC+9+f761//6i7AQTt37nTl1AVQ8ylg0IVNX8ZhrF+/3n3x9ezZ0wUaL730krvo6iKv4MeveVAQqIuw9ue5555rS5Yscb/St23b5r5Qs2p/h123vrR0UVcQqNyWCy+80ObMmeO2KTW33nqr228KQlTLqvLoiybotttusxo1arhmFf8LUjW0+sLT/uvfv78L8EeMGOGOT607dj8r8NI2qNZD59FNN91kkydPdgHKAw884ObT+2+//Xb79ttvXQ1sSg4ePOi+PLUuBcmXXHKJC5gUtGzZssUF0Wm1Z88eVwOt5iGV0T9mZerUqe6Yvvfee92XqAKlsMeyr2/fvi7wTEpKcseoPjs1i/q1PHquebTv1WQqwTKkROXyg8UgNbuFrRVTs9h7773nriOxTXyxFHhcd911dtlll9no0aNt7ty5bpt0riqA8un8v/nmm90PTR3XM2fOdMeRrl0KdkTXLB1H+uGifSsKTlOi+XVM63qsHw86P5ReoWuzzjE/4PfLqfmaNGnijrf333/fxo4d65Z///33u2uG3qu/9VnpPBD9MJUOHTq4z1ifiZara432z6ZNm6LWk2d5yHOmTp2qq7/3/vvve7t27fI2b97szZw50zvrrLO8IkWKeFu2bHHzdevWzc33+OOPR73/v//9r5v+yiuvRE2fO3du1PSdO3d6BQsW9G644QbvxIkTkfmeeOIJN5+W71u4cKGbpv/l2LFjXrVq1bwqVap4P/30U9R6gsvq3bu3e1+srChjPBs3bnTzBfebfPLJJ276I488EpnWsmVLr27dut5vv/0WtS3NmjXzatSoEZn28MMPu/dqGT6Vs2TJkm661ilz5sxxzz/99FMvrbRf9d4PP/wwah2FChXy+vfvH5k2bNgwr1ixYt53330X9X4dEwUKFPA2bdqUZfs77Lrfeust997Ro0dH5tHx07x5czddx3uYz/CZZ56Jmp6UlOSmd+7cOWr6qlWr3PR77rknavqAAQPc9A8++CDZfl6yZElk2rx58yLHzA8//BCZ/pe//CXqHEjJ4MGD3Xxvvvlmstf8feqf4/6xktJ5Ji1atHDTJk+eHHe/lChRwn1uQWGPZb8crVq1ivq8dV7oM9y3b19k2kUXXeTKEpaWm9JjxowZkfl0TOk4Ssnnn3+e7FyNx78e9u3bN2qbdSzrmNa11Hfo0KGo9x45csSrU6eOd80110RNV7niXWNiP7+ff/7ZK1WqlNerV6+o+bZv3+6uC8HpfjmfeuqpqHkvvvhir2HDhpHnKq/m03EepOttvPMB/4emujysVatW7peHmkH0S1O/9vRrWb8ig/SrJEjV2moSUWKmfu35D9VUaBkLFy508+lXjn5t6VdLsAlNTS+p0S8o1Vho3tjck+CyUnIqyhikX9rB/aZfkfq1p+R12bt3r33wwQeuRkE1U3559EtfvwzVHV41K6L36BetluHT5+Q3k/r8/aJfsUePHrW0ql27tqu5CK6jZs2arikiuB81j2oLgvtRx45+1X744YdZtr/Drlv7SzksweNU+SFaR2YI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33/f6tWrF5nuv0/LUK+64DIbNGgQd1mFChVyDwAAgGxb41SwYEFr2LChLViwIDJNyeF63rRp0xTfp15zw4YNs7lz51qjRo2iXlMvOgVPwWUqZ+mTTz456TIBAACy/XAEGoqgW7duLgBq3LixG47gl19+sR49erjX1VNOwwwoD0k0/IDGaHr11Vfd2E9+3tIZZ5zhHrqz8cMPP2zDhw+3GjVqRIYjUB5U+/btE7qtAAAgZ0t44NSxY0fbtWuXC4YUBKk5TTVJfnL3pk2bXE8736RJk1xvvN/97ndRy0lKSrIhQ4a4vx977DEXfN177722b98+u+KKK9wyGcMJAADk6HGcsiPGcUJOwzhOAJAHxnECAADISQicAAAAckqOE5DX0KwGADkXNU4AAAAhETgBAACEROAEAAAQEoETAABASAROAAAAIRE4AQAAhETgBAAAEBKBEwAAQEgETgAAACEROAEAAIRE4AQAABASgRMAAEBIBE4AAAAhETgBAACEROAEAAAQEoETAABASAROAAAAIZ0WdkYAecu1t/XO8DLmz56YKWUBgOyCGicAAICQCJwAAABCInACAAAIicAJAAAgJAInAACAkAicAAAAQiJwAgAACInACQAAICQCJwAAgJAInAAAAEIicAIAAMgpgdPEiROtatWqVrhwYWvSpIktX748xXm//vpr69Chg5s/X758Nm7cuGTzDBkyxL0WfNSqVSuLtwIAAOQFCQ2cZs2aZf369bOkpCRbuXKl1a9f39q0aWM7d+6MO/+hQ4esevXqNnLkSCtfvnyKy73ooots27ZtkcdHH32UhVsBAADyioQGTs8++6z16tXLevToYbVr17bJkydb0aJF7aWXXoo7/6WXXmrPPPOMderUyQoVKpTick877TQXWPmPMmXKZOFWAACAvCJhgdORI0dsxYoV1qpVq/8rTP787vnSpUsztOx169ZZxYoVXe1Uly5dbNOmTSed//Dhw3bgwIGoBwAAQLYJnHbv3m3Hjx+3cuXKRU3X8+3bt6d7ucqTmjZtms2dO9cmTZpkGzdutObNm9vPP/+c4ntGjBhhJUuWjDzOOeecdK8fAADkXglPDs9sbdu2tdtuu83q1avn8qXeffdd27dvn7322mspvmfgwIG2f//+yGPz5s2ntMwAACBnOC1RK1beUYECBWzHjh1R0/X8ZInfaVWqVCm74IILbP369SnOo3ypk+VMAQAApLvGaeHChRneewULFrSGDRvaggULItNOnDjhnjdt2jTTPp2DBw/ahg0brEKFCpm2TAAAkDelK3C67rrr7LzzzrPhw4dnqFlLQxFMmTLFpk+fbmvWrLH777/ffvnlF9fLTrp27eqa0YIJ5atWrXIP/f3jjz+6v4O1SQMGDLDFixfb999/b0uWLLFbbrnF1Wx17tw53eUEAABId+CkgKVPnz72+uuvu55ryiVSDpGCmbTo2LGjjRkzxgYPHmwNGjRwQZCSuv2EcfWG0zhMvq1bt9rFF1/sHpqu9+rve+65JzLPli1bXJBUs2ZNu/322+2ss86yZcuW2dlnn80nDgAAMiSf53leRhaggSunTp1qM2bMcM/vuOMO69mzpxvMMqfScATqXadE8RIlSiS6OMhlrr2td4aXMX/2xBy5TADI6d/7Ge5Vd8kll7jmNNVAKZ9Ig1cqd0lDAOgWKQAAALlFugOno0ePuqa666+/3qpUqWLz5s2zCRMmuF5xyjnSNA0LAAAAkKeHI+jbt69rmlMr31133WWjR4+2OnXqRF4vVqyYyz/S6N0AAAB5OnD65ptv7Pnnn7dbb701xfGPNE5TZgxbAAAAkKOb6pKSklwzXGzQdOzYMfvwww8jN9pt0aJF5pQSAAAgpwZOV199te3duzfZdGWj6zUAAIDcKF1NdcptypcvX7Lpe/bscflNQG5Bl3wAQLoDJ+U0iYKm7t27RzXVHT9+3FavXm3NmjVLyyIBAAByZ+CkwaH8GqfixYtbkSJFou49d9lll1mvXr0yv5QAAAA5LXDSCOFStWpVd084muUAAEBeclp6e9UBAADkNael5dYqCxYssNKlS7sb68ZLDg/evw4AACDPBk7t2rWLJIO3b98+K8sEAACQswOnYPMcTXUAACAvSvdNfgEAAPKa0DVOym06WV5TULxRxQEAAPJM4DRu3LisLQkAAEBuCZy6deuWtSUBAADILYHTgQMHrESJEpG/T8afDwAAIM/mOG3bts3Kli1rpUqVipvv5N/8V/etAwAAyLOB0wcffGBnnnmm+3vhwoVZWSYAAICcHTi1aNEi7t8AAAB5RbruVSc//fST/e1vf7M1a9a457Vr17YePXpEaqUAAABym3QNgPnhhx9a1apVbfz48S6A0kN/V6tWzb0GAACQG6Wrxql3797WsWNHmzRpkhUoUMBNU0L4Aw884F778ssvM7ucAAAAObPGaf369da/f/9I0CT6u1+/fu41AACA3ChdgdMll1wSyW0K0rT69etnRrkAAAByblPd6tWrI38/+OCD9tBDD7napcsuu8xNW7ZsmU2cONFGjhyZNSUFAADIKYFTgwYN3OCWGuTS99hjjyWb74477nD5TwAQz7W39c7wMubPnpgpZQGALAucNm7cmOaFAwAA5MnAqUqVKllbEgAAgNw6AKZ88803tmnTJjty5EjU9Jtvvjmj5QIAAMgdver+97//ud5zderUsRtuuMHat2/vHrfccot7pIUSyjWYZuHCha1Jkya2fPnyFOf9+uuvrUOHDm5+5VuNGzcuw8sEAADI0sBJPeo0SvjOnTutaNGiLqDRiOGNGjWyRYsWhV7OrFmz3NhPSUlJtnLlSheMtWnTxi03nkOHDln16tVdz73y5ctnyjIBAACyNHBaunSpPfXUU1amTBnLnz+/e1xxxRU2YsQIN1RBWM8++6z16tXL3eNO97qbPHmyC8ReeumluPNfeuml9swzz1inTp2sUKFCmbJMAACALA2cdHuV4sWLu78VPG3dujWSQP7tt9+GWobyolasWGGtWrX6v8Lkz++eKzBLj/Qu8/Dhw3bgwIGoBwAAQKYETspt+uKLL9zfyiEaPXq0ffzxx64WSk1pYezevdsFYOXKlYuarufbt29PT7HSvUzVlJUsWTLyOOecc9K1fgAAkLulK3B68skn7cSJE+5vBUsa46l58+b27rvv2vjx4y2nGThwoO3fvz/y2Lx5c6KLBAAAcstwBEq29p1//vm2du1a27t3r5UuXdr1dgtDTXy6MfCOHTuiput5SonfWbVM5UullDMFAACQoRqnINXO6HHmmWeGDpqkYMGC1rBhQ1uwYEFkmmqx9Lxp06bpKktWLBMAACBDgdOxY8ds0KBBLh9I4yXpob/VhHf06NHQy9GwAVOmTLHp06fbmjVr7P7777dffvnF9YiTrl27uma0YPL3qlWr3EN///jjj+5v3Ww47DIBAABOaVNd37597c0333RJ4X5NjnqtDRkyxPbs2WOTJk0KtRzdDHjXrl02ePBgl7ytGwnPnTs3ktytUcnVK86n3nsXX3xx5PmYMWPco0WLFpHxo1JbJgAAwCkNnF599VWbOXOmtW3bNjKtXr16rjda586dQwdO0qdPH/eIJ3YwTdVseZ6XoWUCAACc0qY6JVIriIml0cSVZwQAAJAbpStwUm3OsGHD3MCRPv399NNPU9MDAAByrdBNdbfeemvU8/fff98qV67s7gUnGhBTCdstW7bM/FICAADkpMBJveaCOnToEPWc0bYBAEBuFzpwmjp1ataWBAAAIDf2qvOp279/U9+aNWva2WefnVnlAgAAyB3J4RpQ8u6777YKFSrYlVde6R4VK1a0nj172qFDhzK/lAAAADk1cNLo3IsXL7Z//etftm/fPvd4++233bT+/ftnfikBAAByalPdG2+8Ya+//rpdddVVkWnXX3+9FSlSxG6//fY0DYAJAACQq2uc1BwX7xYmZcuWpakOAADkWukKnHR/uqSkJPvtt98i03799VcbOnRo5N51AAAAuU26murGjRtn1113XbIBMAsXLmzz5s3L7DICAADk3MCpbt26tm7dOnvllVds7dq1bppu7tulSxeX5wQAAJAbpTlwOnr0qNWqVcveeecd69WrV9aUCgAAIDfkOJ1++ulRuU0AAAB5RbqSw3v37m2jRo2yY8eOZX6JAAAAclOO06effmoLFiyw9957z+U7FStWLOr1N998M7PKBwAAkLMDp1KlSlmHDh0yvzQAAAC5JXA6ceKEPfPMM/bdd9/ZkSNH7JprrrEhQ4bQkw4Jd+1tvTO8jPmzJ2ZKWQAAuVeacpyefvppe+KJJ+yMM86wSpUq2fjx412+EwAAQF6QpsDp5ZdfthdeeMENcvnWW2+5m/xqLCfVRAEAAOR2aQqcNm3a5G7m62vVqpXly5fPtm7dmhVlAwAAyLmBk4Yf0G1VYsd10qCYAAAAuV2aksM9z7Pu3btboUKFItM0GOZ9990XNSQBwxEAAADL64FTt27dkk278847M7M8AAAAuSNwmjp1ataVBAAAIDfecgUAACAvInACAAAIicAJAAAgJAInAACAkAicAAAAsqJXXVaZOHGiu3nw9u3brX79+vb8889b48aNU5x/9uzZNmjQIPv++++tRo0aNmrUqKgRzTXW1PTp06Pe06ZNG5s7d26WbgeAxOAmzwDyTI3TrFmzrF+/fpaUlGQrV650gZOCnJ07d8adf8mSJda5c2fr2bOnff7559a+fXv3+Oqrr6Lmu+6662zbtm2Rx4wZM07RFgEAgNwq4YHTs88+a7169bIePXpY7dq1bfLkyVa0aFF76aWX4s7/3HPPuaDo0UcftQsvvNCGDRtml1xyiU2YMCFqPo1uXr58+cijdOnSp2iLAABAbpXQwOnIkSO2YsUKd7PgSIHy53fPly5dGvc9mh6cX1RDFTv/okWLrGzZslazZk27//77bc+ePVm0FQAAIK9IaI7T7t277fjx41auXLmo6Xq+du3auO9RHlS8+TXdpxqpW2+91apVq2YbNmywJ554wtq2beuCqwIFCiRb5uHDh93Dd+DAgUzYOgAAkNtki+TwzNapU6fI33Xr1rV69erZeeed52qhWrZsmWz+ESNG2NChQ09xKQEAQE6T0Ka6MmXKuBqgHTt2RE3Xc+UlxaPpaZlfqlev7ta1fv36uK8PHDjQ9u/fH3ls3rw5XdsDAAByt4QGTgULFrSGDRvaggULItNOnDjhnjdt2jTuezQ9OL/Mnz8/xflly5YtLsepQoUKcV9XInmJEiWiHgAAANmuV52GIpgyZYobd2nNmjUukfuXX35xveyka9eurkbI99BDD7nxmMaOHevyoIYMGWKfffaZ9enTx71+8OBB1+Nu2bJlbpwnBVnt2rWz888/3yWRAwAA5Ngcp44dO9quXbts8ODBLsG7QYMGLjDyE8A3bdrketr5mjVrZq+++qo9+eSTLulbA2C+9dZbVqdOHfe6mv5Wr17tArF9+/ZZxYoVrXXr1m7YAtUsAQAA5NjASVRb5NcYxVJCd6zbbrvNPeIpUqSIzZs3L9PLCAAAkPCmOgAAgJyCwAkAACAkAicAAICQCJwAAABCInACAAAIicAJAAAgJAInAACAkAicAAAAQiJwAgAACInACQAAICQCJwAAgJAInAAAAEIicAIAAAiJwAkAACCk08LOCGSWa2/rneFlzJ89MVPKAgBAWlDjBAAAEBKBEwAAQEgETgAAACGR4wQAcZCLByAeapwAAABCInACAAAIicAJAAAgJAInAACAkAicAAAAQiJwAgAACInACQAAICQCJwAAgJAInAAAAEIicAIAAAiJwAkAACAkAicAAICQuMkvToobnQKZh/MJyPmyRY3TxIkTrWrVqla4cGFr0qSJLV++/KTzz54922rVquXmr1u3rr377rtRr3ueZ4MHD7YKFSpYkSJFrFWrVrZu3bos3goAAJDbJTxwmjVrlvXr18+SkpJs5cqVVr9+fWvTpo3t3Lkz7vxLliyxzp07W8+ePe3zzz+39u3bu8dXX30VmWf06NE2fvx4mzx5sn3yySdWrFgxt8zffvvtFG4ZAADIbRIeOD377LPWq1cv69Gjh9WuXdsFO0WLFrWXXnop7vzPPfecXXfddfboo4/ahRdeaMOGDbNLLrnEJkyYEKltGjdunD355JPWrl07q1evnr388su2detWe+utt07x1gEAgNwkoTlOR44csRUrVtjAgQMj0/Lnz++a1pYuXRr3PZquGqog1Sb5QdHGjRtt+/btbhm+kiVLuiZAvbdTp05Ztj0AkAjkTgF5JHDavXu3HT9+3MqVKxc1Xc/Xrl0b9z0KiuLNr+n+6/60lOaJdfjwYffw7d+/3/1/4MAByynade2f4WW8/fLYZNOOHT2S4eXG7secssysWm5eXmZWLTcvLzOrlptV1xQgO/KPf7VapYZedWY2YsQIGzp0aLLp55xzjuUlJUu+mGOWm1OWmVXLzcvLzKrl5uVl5rSyAlnl559/dq1U2TZwKlOmjBUoUMB27NgRNV3Py5cvH/c9mn6y+f3/NU296oLzNGjQIO4y1VQYbP47ceKE7d2718466yzLly+fJSLyVdC2efNmK1GixClfP8Lhc8oZ+JxyDj6rnOFALvycVNOkoKlixYqpzpvQwKlgwYLWsGFDW7BggesZ5wctet6nT5+472natKl7/eGHH45Mmz9/vpsu1apVc8GT5vEDJX3I6l13//33x11moUKF3COoVKlSlmg6IHPLQZmb8TnlDHxOOQefVc5QIpd9TqnVNGWbpjrV9HTr1s0aNWpkjRs3dj3ifvnlF9fLTrp27WqVKlVyzWny0EMPWYsWLWzs2LF2ww032MyZM+2zzz6zv/71r+511RApqBo+fLjVqFHDBVKDBg1yUaQfnAEAAKRHwgOnjh072q5du9yAlUreVi3R3LlzI8ndmzZtcj3tfM2aNbNXX33VDTfwxBNPuOBIPerq1KkTmeexxx5zwde9995r+/btsyuuuMItUwNmAgAApFc+L0wKOU4p9fBTDZtyr2KbEJF98DnlDHxOOQefVc5wOI9/TgROAAAAOWXkcAAAgJyCwAkAACAkAicAAICQCJyymYkTJ1rVqlVdD0DdX2/58uWJLhJiDBkyxA17EXzUqlUr0cXK8z788EO76aab3NAj+kxib+qtdE713tXAuEWKFHH3s1y3bl3CyptXpfY5de/ePdn5pRu749RS8vell15qxYsXt7Jly7rhfL799tuoeX777Tfr3bu3Gyz6jDPOsA4dOiQboDo3InDKRmbNmuXGtUpKSrKVK1da/fr13Q2Md+7cmeiiIcZFF11k27Ztizw++uijRBcpz9MQJDpn9OMjntGjR9v48eNt8uTJbkDcYsWKufNLF39kn89JFCgFz68ZM2ac0jLCbPHixS4oWrZsmRtk+ujRo9a6dWv3+fkeeeQR+9e//mWzZ89282/dutVuvfVWy/XUqw7ZQ+PGjb3evXtHnh8/ftyrWLGiN2LEiISWC9GSkpK8+vXrJ7oYOAld2ubMmRN5fuLECa98+fLeM888E5m2b98+r1ChQt6MGTMSVErEfk7SrVs3r127dgkrE+LbuXOn+7wWL14cOX9OP/10b/bs2ZF51qxZ4+ZZunSpl5tR45RNHDlyxFasWOGaD3wa+FPPly5dmtCyITk18aipoXr16talSxc3UCuyr40bN7oBdoPnl26voOZwzq/sZ9GiRa55qGbNmu5WWXv27El0kfK8/fv3u//PPPNM97++r1QLFTynlLJw7rnn5vpzisApm9i9e7cdP348MmK6T891wUf2oS/badOmudHoJ02a5L6Umzdv7m4QiezJP4c4v7I/NdO9/PLL7n6jo0aNck1Abdu2dddHJIbuIatbmV1++eWRu3TovNH9ZmPv65oXzqmE33IFyGl0EffVq1fPBVJVqlSx1157zXr27JnQsgE5XadOnSJ/161b151j5513nquFatmyZULLllcp1+mrr74il/P/ocYpmyhTpowVKFAgWY8EPS9fvnzCyoXU6RfXBRdcYOvXr090UZAC/xzi/Mp51Byu6yPnV2L06dPH3nnnHVu4cKFVrlw5Ml3njVJMdD/YvHZOEThlE6rybNiwoaueDlaP6nnTpk0TWjac3MGDB23Dhg2umzuyp2rVqrmLefD8OnDggOtdx/mVvW3ZssXlOHF+nVrK3VfQNGfOHPvggw/cORTUsGFDO/3006POKQ1XoHzP3H5O0VSXjWgogm7dulmjRo2scePGNm7cONf1s0ePHokuGgIGDBjgxqFR85y632r4CNUWdu7cOdFFs7wewAZrJZR7tmrVKpfMqoRV5WgMHz7catSo4b4EBg0a5BL8NT4NssfnpMfQoUPdeEAKdPWD5LHHHrPzzz/fDR2BU9s89+qrr9rbb7/txnLy85ZKlizpxkHT/0pN0PeWPrcSJUpY3759XdB02WWXWa6W6G59iPb888975557rlewYEE3PMGyZcsSXSTE6Nixo1ehQgX3GVWqVMk9X79+faKLlectXLjQdYWOfah7uz8kwaBBg7xy5cq5YQhatmzpffvtt4kudp5zss/p0KFDXuvWrb2zzz7bdXWvUqWK16tXL2/79u2JLnaeE+8z0mPq1KmReX799VfvgQce8EqXLu0VLVrUu+WWW7xt27Z5uV0+/ZPo4A0AACAnIMcJAAAgJAInAACAkAicAAAAQiJwAgAACInACQAAICQCJwAAgJAInAAAAEIicAIAAAiJwAlAjvP9999bvnz53K06sou1a9e6W00ULlzYGjRoEHeeq666yt36JbNNmzbN3WwaQNYjcAKQZt27d3eBy8iRI6Omv/XWW256XqR7FhYrVszd6DR441MAuQuBE4B0Uc3KqFGj7KeffrLc4siRI+l+r25Ie8UVV7ibP5911lmZWi4A2QeBE4B0adWqlbuD/YgRI1KcZ8iQIcmarcaNG2dVq1aNqr1q3769/elPf7Jy5cq5JqennnrKjh07Zo8++qi783rlypVt6tSpcZvHmjVr5oK4OnXq2OLFi6Ne/+qrr6xt27Z2xhlnuGXfddddtnv37qimsz59+rjmszJlylibNm3ibseJEydcmVSOQoUKuW2aO3du5HXVsq1YscLNo7+13SnRdmmduru81jlo0CDdbD3y+uHDh23AgAFWqVIlV4PVpEkTW7RoUbKmuXPPPdeKFi1qt9xyi+3Zsyfq9S+++MKuvvpqd1d73bW+YcOG9tlnn6VYJgDhETgBSJcCBQq4YOf555+3LVu2ZGhZH3zwgW3dutU+/PBDe/bZZ12z14033milS5e2Tz75xO677z77/e9/n2w9Cqz69+9vn3/+uTVt2tRuuummSBCxb98+u+aaa+ziiy92QYMCnR07dtjtt98etYzp06dbwYIF7eOPP7bJkyfHLd9zzz1nY8eOtTFjxtjq1atdgHXzzTfbunXr3Ovbtm2ziy66yJVFfyvwSYnWd9ppp9ny5cvdcrW9L774YuR1BVVLly61mTNnunXddtttdt1110XWpf3Rs2dPN59yvBQgDR8+PGodXbp0cUHep59+6gK6xx9/3E4//fQ0fy4A4vAAII26devmtWvXzv192WWXeXfffbf7e86cOao6icyXlJTk1a9fP+q9f/7zn70qVapELUvPjx8/HplWs2ZNr3nz5pHnx44d84oVK+bNmDHDPd+4caNbz8iRIyPzHD161KtcubI3atQo93zYsGFe69ato9a9efNm975vv/3WPW/RooV38cUXp7q9FStW9J5++umoaZdeeqn3wAMPRJ5rO7W9J6P1XXjhhd6JEyci0/7whz+4afLDDz94BQoU8H788ceo97Vs2dIbOHCg+7tz587e9ddfH/V6x44dvZIlS0aeFy9e3Js2bVqq2wUg7ahxApAhynNSLcqaNWvSvQzV1uTP/3+XIzWr1a1bN6p2S3lDO3fujHqfapl8qsVp1KhRpBxqrlq4cKFrpvMftWrViuQj+dSMdTIHDhxwtWGXX3551HQ9T882q+ddMIFe26DapOPHj9uXX37p/r/ggguiyq0mSL/MWqea71LaD9KvXz+75557XHOqEviD2wsgY07L4PsB5HFXXnmla7oaOHCgy1cKUjAUzN+Ro0ePJltGbDOSAot405RrFNbBgwdd050Cu1gVKlSI/K08ouxCZVaQqOY1/R+kACos5Vjdcccd9u9//9v+85//uKZPNf0pHwpAxhA4Acgw1WooYbpmzZpR088++2zbvn27C578WpbMHHtp2bJlLnDzk64VcCj3Ry655BJ74403XCK6aqPSS8nVFStWdDlQLVq0iEzX88aNG6d5ecpRit2GGjVquEBJ+ViqcVLNWvPmzeO+/8ILL4y7jFiqtdLjkUcesc6dO7vkegInIONoqgOQYWpWU0Ly+PHjo6ar19quXbts9OjRrrlo4sSJrgYks2h5c+bMcb3revfu7YZGuPvuu91rer53714XNChJWuufN2+e9ejRwwUnaaEkdNVczZo1y43TpGRrBYAPPfRQmsu8adMm15Sm5cyYMcMl1/vLUaCj/di1a1d78803bePGjS6JXD0XVXskDz74oEt0V6K6mvgmTJgQ1cPv119/dcGjeuL98MMPLsDT9ivgApBxBE4AMoW64sc2penL+oUXXnABTv369V0QcLIeZ+mp6dJDy/7oo4/sn//8p+viL34tkYKk1q1bu+BOww5ouINgPlUYClYU7KjXnJajQEXrUk1RWikoUnCj2ioFdwqa7r333sjrqhnSPFqXavA0VIMCHw0/4OdITZkyxfXI03a/99579uSTT0ber5or9SzUMhSIqRehhmQYOnRomssKILl8yhCPMx0AAAAxqHECAAAIicAJAAAgJAInAACAkAicAAAAQiJwAgAACInACQAAICQCJwAAgJAInAAAAEIicAIAAAiJwAkAACAkAicAAICQCJwAAAAsnP8P8GN1HUU6zDwAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "title = (\n", + " f'Predicted beds needed from current ED patients\\n'\n", + " f'at {format_prediction_time(prediction_time)} '\n", + " f'on {snapshot_date}'\n", + ")\n", + "plot_prob_dist(arrivals.probabilities, title, include_titles=True)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "This is the same distribution as Step 1 — the `DemandPredictor` simply passes through the PMF when there is only one flow selected. The value is in what it provides: summary statistics (expectation, mode, percentiles) and the ability to combine multiple flows, as we'll see next." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Step 6: Use `FlowSelection` to control which flows are included\n", + "\n", + "The `FlowSelection` class is a toggle for which flows to include in a prediction. It provides several presets and a `custom()` method for full control.\n", + "\n", + "Let's combine current ED patients with yet-to-arrive patients. This is where convolution happens — the `DemandPredictor` convolves the PMF from current patients with the Poisson distribution from yet-to-arrive patients to produce a single combined distribution." + ] + }, + { + "cell_type": "code", + "execution_count": 40, + "metadata": { + "execution": { + "iopub.execute_input": "2026-02-23T08:42:53.242705Z", + "iopub.status.busy": "2026-02-23T08:42:53.242573Z", + "iopub.status.idle": "2026-02-23T08:42:53.257443Z", + "shell.execute_reply": "2026-02-23T08:42:53.257053Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Current ED only — expected beds: 6.9\n", + "Yet-to-arrive only — Poisson rate: 18.6\n", + "Combined — expected beds: 25.5\n" + ] + } + ], + "source": [ + "# Include both current ED and yet-to-arrive patients\n", + "combined_bundle = predictor.predict_service(\n", + " inputs=service_inputs,\n", + " flow_selection=FlowSelection.custom(\n", + " include_ed_current=True,\n", + " include_ed_yta=True,\n", + " include_non_ed_yta=False,\n", + " include_elective_yta=False,\n", + " include_transfers_in=False,\n", + " include_departures=False,\n", + " cohort='emergency'\n", + " )\n", + ")\n", + "\n", + "print(f'Current ED only — expected beds: {current_ed_bundle.arrivals.expectation:.1f}')\n", + "print(f'Yet-to-arrive only — Poisson rate: {yta_lambda:.1f}')\n", + "print(f'Combined — expected beds: {combined_bundle.arrivals.expectation:.1f}')\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The expected value of the combined distribution equals the sum of the individual expected values — a property of convolution. But the full probability distribution captures the combined uncertainty, not just the means." + ] + }, { - "name": "stdout", - "output_type": "stream", - "text": [ - "ED current: True\n", - "ED yet-to-arrive: True\n", - "Non-ED YTA: False\n", - "Elective YTA: False\n", - "Transfers in: False\n", - "Departures: False\n", - "Cohort: emergency\n" - ] + "cell_type": "code", + "execution_count": 41, + "metadata": { + "execution": { + "iopub.execute_input": "2026-02-23T08:42:53.258681Z", + "iopub.status.busy": "2026-02-23T08:42:53.258601Z", + "iopub.status.idle": "2026-02-23T08:42:53.338724Z", + "shell.execute_reply": "2026-02-23T08:42:53.338349Z" + } + }, + "outputs": [ + { + "data": { + "image/png": "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", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "title = (\n", + " f'Predicted beds needed from current ED and yet-to-arrive patients\\n'\n", + " f'at {format_prediction_time(prediction_time)} '\n", + " f'on {snapshot_date}'\n", + ")\n", + "plot_prob_dist(\n", + " combined_bundle.arrivals.probabilities, title,\n", + " include_titles=True,\n", + " probability_levels=[0.75, 0.25],\n", + " show_probability_thresholds=True,\n", + " bar_colour='orange'\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now let's compare two presets — `FlowSelection.incoming_only()` includes all inflows but no departures, while `FlowSelection.default()` includes everything." + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": { + "execution": { + "iopub.execute_input": "2026-02-23T08:42:53.340259Z", + "iopub.status.busy": "2026-02-23T08:42:53.340163Z", + "iopub.status.idle": "2026-02-23T08:42:53.356429Z", + "shell.execute_reply": "2026-02-23T08:42:53.355991Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "=== FlowSelection.incoming_only() ===\n", + " Expected arrivals: 25.5\n", + " Expected departures: 0.0\n", + " Expected net flow: 25.5\n", + "\n", + "=== FlowSelection.default() ===\n", + " Expected arrivals: 25.5\n", + " Expected departures: 7.0\n", + " Expected net flow: 18.5\n" + ] + } + ], + "source": [ + "incoming_bundle = predictor.predict_service(\n", + " inputs=service_inputs,\n", + " flow_selection=FlowSelection.incoming_only()\n", + ")\n", + "\n", + "default_bundle = predictor.predict_service(\n", + " inputs=service_inputs,\n", + " flow_selection=FlowSelection.default()\n", + ")\n", + "\n", + "print('=== FlowSelection.incoming_only() ===')\n", + "print(f' Expected arrivals: {incoming_bundle.arrivals.expectation:.1f}')\n", + "print(f' Expected departures: {incoming_bundle.departures.expectation:.1f}')\n", + "print(f' Expected net flow: {incoming_bundle.net_flow.expectation:.1f}')\n", + "print()\n", + "print('=== FlowSelection.default() ===')\n", + "print(f' Expected arrivals: {default_bundle.arrivals.expectation:.1f}')\n", + "print(f' Expected departures: {default_bundle.departures.expectation:.1f}')\n", + "print(f' Expected net flow: {default_bundle.net_flow.expectation:.1f}')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The available presets are:\n", + "- `FlowSelection.default()` — all flows\n", + "- `FlowSelection.incoming_only()` — all inflows, no departures\n", + "- `FlowSelection.outgoing_only()` — only departures\n", + "- `FlowSelection.emergency_only()` — only emergency-related flows\n", + "- `FlowSelection.elective_only()` — only elective-related flows\n", + "- `FlowSelection.custom(...)` — full control over individual flow families" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Step 7: The `PredictionBundle` — arrivals, departures, and net flow\n", + "\n", + "Every call to `predictor.predict_service()` returns a `PredictionBundle`. This bundles together three `DemandPrediction` objects:\n", + "\n", + "- **arrivals** — the combined inflow distribution\n", + "- **departures** — the combined outflow distribution\n", + "- **net_flow** — the difference (arrivals minus departures)\n", + "\n", + "It also records which `FlowSelection` was used, so you can always trace what went into the prediction. The bundle's **`is_aspirational`** flag is `True` when any contributing inflow was generated under aspirational assumptions (e.g. ED performance targets), indicating that comparison against observed admissions requires care — see notebook 4d." + ] + }, + { + "cell_type": "code", + "execution_count": 43, + "metadata": { + "execution": { + "iopub.execute_input": "2026-02-23T08:42:53.357774Z", + "iopub.status.busy": "2026-02-23T08:42:53.357687Z", + "iopub.status.idle": "2026-02-23T08:42:53.370932Z", + "shell.execute_reply": "2026-02-23T08:42:53.370607Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "PredictionBundle(service: medical)\n", + " Arrivals: PMF[20:30]: [0.046, 0.057, 0.068, 0.077, 0.082, 0.085, 0.083, 0.078, 0.070, 0.061] (E=25.5)\n", + " Departures: PMF[0:1]: [1.000] (E=0.0)\n", + " Net flow: PMF[20:30]: [0.046, 0.057, 0.068, 0.077, 0.082, 0.085, 0.083, 0.078, 0.070, 0.061] (E=25.5)\n", + " Flows: selection cohort=emergency inflows(ed_current=True, ed_yta=True, non_ed_yta=False, elective_yta=False, transfers_in=False) outflows(departures=False)\n" + ] + } + ], + "source": [ + "print(combined_bundle)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Each `DemandPrediction` carries useful summary statistics:" + ] + }, + { + "cell_type": "code", + "execution_count": 44, + "metadata": { + "execution": { + "iopub.execute_input": "2026-02-23T08:42:53.372312Z", + "iopub.status.busy": "2026-02-23T08:42:53.372241Z", + "iopub.status.idle": "2026-02-23T08:42:53.385668Z", + "shell.execute_reply": "2026-02-23T08:42:53.385298Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Expected beds: 25.5\n", + "Most likely (mode): 25\n", + "Percentiles: {25: 22, 50: 25, 75: 29}\n", + "90% probability: need at least 20 beds\n", + "PMF array length: 76\n" + ] + } + ], + "source": [ + "arrivals = combined_bundle.arrivals\n", + "\n", + "print(f'Expected beds: {arrivals.expectation:.1f}')\n", + "print(f'Most likely (mode): {arrivals.mode}')\n", + "print(f'Percentiles: {arrivals.percentiles}')\n", + "print(f'90% probability: need at least {arrivals.min_beds_with_probability(0.9)} beds')\n", + "print(f'PMF array length: {len(arrivals.probabilities)}')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The `flow_selection` attribute records which flows were included:" + ] + }, + { + "cell_type": "code", + "execution_count": 45, + "metadata": { + "execution": { + "iopub.execute_input": "2026-02-23T08:42:53.387048Z", + "iopub.status.busy": "2026-02-23T08:42:53.386972Z", + "iopub.status.idle": "2026-02-23T08:42:53.400890Z", + "shell.execute_reply": "2026-02-23T08:42:53.400519Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "ED current: True\n", + "ED yet-to-arrive: True\n", + "Non-ED YTA: False\n", + "Elective YTA: False\n", + "Transfers in: False\n", + "Departures: False\n", + "Cohort: emergency\n" + ] + } + ], + "source": [ + "fs = combined_bundle.flow_selection\n", + "print(f'ED current: {fs.include_ed_current}')\n", + "print(f'ED yet-to-arrive: {fs.include_ed_yta}')\n", + "print(f'Non-ED YTA: {fs.include_non_ed_yta}')\n", + "print(f'Elective YTA: {fs.include_elective_yta}')\n", + "print(f'Transfers in: {fs.include_transfers_in}')\n", + "print(f'Departures: {fs.include_departures}')\n", + "print(f'Cohort: {fs.cohort}')" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Summary\n", + "\n", + "In this notebook we traced the path from familiar 3x_ outputs to the structured data classes used in the 4x_ notebooks:\n", + "\n", + "| 3x_ concept | 4x_ equivalent | What changed? |\n", + "|---|---|---|\n", + "| Raw PMF array from `get_prob_dist_for_prediction_moment()` | `FlowInputs(flow_type=\"pmf\", distribution=pmf_array)` | Same numbers, named container |\n", + "| Poisson distribution from yet-to-arrive model | `FlowInputs(flow_type=\"poisson\", distribution=lambda)` | Rate stored; full distribution regenerated when needed |\n", + "| Manual `np.convolve()` of multiple distributions | `DemandPredictor.predict_service()` | Same maths, handled automatically |\n", + "| Ad-hoc selection of which inputs to include | `FlowSelection.incoming_only()`, `.default()`, `.custom(...)` | Explicit, reproducible toggle |\n", + "| Individual result arrays | `PredictionBundle` with arrivals, departures, net flow | Structured output with summary statistics |\n", + "\n", + "In notebook 4c, you'll see how `build_service_data()` constructs all of these automatically from trained models for the full UCLH implementation — building a dictionary of `ServicePredictionInputs` for every specialty in a single call." + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "patientflow", + "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.13.2" } - ], - "source": [ - "fs = combined_bundle.flow_selection\n", - "print(f'ED current: {fs.include_ed_current}')\n", - "print(f'ED yet-to-arrive: {fs.include_ed_yta}')\n", - "print(f'Non-ED YTA: {fs.include_non_ed_yta}')\n", - "print(f'Elective YTA: {fs.include_elective_yta}')\n", - "print(f'Transfers in: {fs.include_transfers_in}')\n", - "print(f'Departures: {fs.include_departures}')\n", - "print(f'Cohort: {fs.cohort}')" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Summary\n", - "\n", - "In this notebook we traced the path from familiar 3x_ outputs to the structured data classes used in the 4x_ notebooks:\n", - "\n", - "| 3x_ concept | 4x_ equivalent | What changed? |\n", - "|---|---|---|\n", - "| Raw PMF array from `get_prob_dist_for_prediction_moment()` | `FlowInputs(flow_type=\"pmf\", distribution=pmf_array)` | Same numbers, named container |\n", - "| Poisson distribution from yet-to-arrive model | `FlowInputs(flow_type=\"poisson\", distribution=lambda)` | Rate stored; full distribution regenerated when needed |\n", - "| Manual `np.convolve()` of multiple distributions | `DemandPredictor.predict_service()` | Same maths, handled automatically |\n", - "| Ad-hoc selection of which inputs to include | `FlowSelection.incoming_only()`, `.default()`, `.custom(...)` | Explicit, reproducible toggle |\n", - "| Individual result arrays | `PredictionBundle` with arrivals, departures, net flow | Structured output with summary statistics |\n", - "\n", - "In notebook 4c, you'll see how `build_service_data()` constructs all of these automatically from trained models for the full UCLH implementation — building a dictionary of `ServicePredictionInputs` for every specialty in a single call." - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "patientflow", - "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.12.4" - } - }, - "nbformat": 4, - "nbformat_minor": 4 + "nbformat": 4, + "nbformat_minor": 4 } diff --git a/src/patientflow/aggregate.py b/src/patientflow/aggregate.py index 2b92943..d228b51 100644 --- a/src/patientflow/aggregate.py +++ b/src/patientflow/aggregate.py @@ -43,6 +43,11 @@ get_prob_dist_using_survival_curve : function Calculate probability distributions for each snapshot date based on given model predictions, using a survival curve to predict the probability of each patient being admitted within a given prediction window. +get_prob_dist_by_service : function + Evaluate composed service-level predictions across the test set for one or more + services, producing probability distributions and observed values in the standard + evaluation format. + """ import pandas as pd @@ -448,28 +453,14 @@ def get_prob_dist( ) prob_dist_dict = {} - if verbose: - print( - f"Calculating probability distributions for {len(snapshots_dict)} snapshot dates" - ) - - if len(snapshots_dict) > 10: - print( - "Using efficient generating function approach - much faster than before!" - ) - - # Initialize a counter for notifying the user every 10 snapshot dates processed - count = 0 for dt, snapshots_to_include in snapshots_dict.items(): if len(snapshots_to_include) == 0: - # Create an empty dictionary for the current snapshot date prob_dist_dict[dt] = { "agg_predicted": pd.DataFrame({"agg_proba": [1]}, index=[0]), "agg_observed": 0, } else: - # Ensure the lengths of test features and outcomes are equal assert len(X_test.loc[snapshots_to_include]) == len( y_test.loc[snapshots_to_include] ), "Mismatch in lengths of X_test and y_test snapshots." @@ -479,7 +470,6 @@ def get_prob_dist( else: prediction_moment_weights = weights.loc[snapshots_to_include].values - # Apply category filter if category_filter is None: prediction_moment_category_filter = None else: @@ -487,7 +477,6 @@ def get_prob_dist( snapshots_to_include ] - # Use the refactored generating function approach prob_dist_dict[dt] = get_prob_dist_for_prediction_moment( X_test=X_test.loc[snapshots_to_include], y_test=y_test.loc[snapshots_to_include], @@ -497,11 +486,6 @@ def get_prob_dist( normal_approx_threshold=normal_approx_threshold, ) - # Increment the counter and notify the user every 10 snapshot dates processed - count += 1 - if verbose and count % 10 == 0 and count != len(snapshots_dict): - print(f"Processed {count} snapshot dates") - if verbose: print(f"Processed {len(snapshots_dict)} snapshot dates") @@ -578,12 +562,7 @@ def get_prob_dist_using_survival_curve( ) prob_dist_dict = {} - if verbose: - print( - f"Calculating probability distributions for {len(snapshot_dates)} snapshot dates" - ) - # Create prediction context that will be the same for all dates prediction_context = {category: {"prediction_time": prediction_time}} for dt in snapshot_dates: @@ -621,3 +600,271 @@ def get_prob_dist_using_survival_curve( print(f"Processed {len(snapshot_dates)} snapshot dates") return prob_dist_dict + + +def prediction_to_eval_dict( + probabilities: "np.ndarray", + observed: int, +) -> Dict[str, Any]: + """Convert a production-format probability array and observed count to the + evaluation dictionary format used by the visualisation functions. + + Parameters + ---------- + probabilities : np.ndarray + Probability mass function array where ``probabilities[k] = P(count = k)``. + Typically obtained from ``DemandPrediction.probabilities``. + observed : int + The observed count for this prediction moment. + + Returns + ------- + Dict[str, Any] + Dictionary with keys ``'agg_predicted'`` (a DataFrame with column + ``'agg_proba'``) and ``'agg_observed'`` (int), compatible with + ``plot_epudd``, ``plot_randomised_pit``, ``qq_plot``, etc. + """ + agg_predicted = pd.DataFrame( + {"agg_proba": probabilities}, + index=range(len(probabilities)), + ) + return {"agg_predicted": agg_predicted, "agg_observed": observed} + + +def _count_observed_admissions( + ed_visits: pd.DataFrame, + snapshot_date: date, + prediction_time: Tuple[int, int], + prediction_window: timedelta, + specialty: Optional[str] = None, +) -> int: + """Count actual admissions for a given snapshot date, prediction time and + (optionally) specialty. + + Parameters + ---------- + ed_visits : pd.DataFrame + Full ED visits dataframe. Must contain columns ``snapshot_date``, + ``prediction_time``, ``is_admitted``, and (when *specialty* is given) + ``specialty``. + snapshot_date : date + The date of the snapshot. + prediction_time : Tuple[int, int] + ``(hour, minute)`` of the prediction moment. + prediction_window : timedelta + Not used for counting (admissions are identified by the ``is_admitted`` + flag on the snapshot), but reserved for future use with time-windowed + counting. + specialty : str, optional + If provided, count only admissions to this specialty. + + Returns + ------- + int + Number of admitted patients matching the criteria. + """ + mask = ( + (ed_visits["snapshot_date"] == snapshot_date) + & (ed_visits["prediction_time"] == prediction_time) + & (ed_visits["is_admitted"].astype(bool)) + ) + if specialty is not None: + mask = mask & (ed_visits["specialty"] == specialty) + return int(mask.sum()) + + +def get_prob_dist_by_service( + ed_visits: pd.DataFrame, + snapshot_dates: List[date], + prediction_time: Tuple[int, int], + models: tuple, + specialties: List[str], + prediction_window: timedelta, + x1: float, + y1: float, + x2: float, + y2: float, + services: Optional[List[str]] = None, + inpatient_visits: Optional[pd.DataFrame] = None, + flow_selection: Optional[Any] = None, + component: str = "arrivals", + verbose: bool = False, +) -> Dict[str, Dict[date, Dict[str, Any]]]: + """Evaluate composed service-level predictions across a set of test dates. + + Unlike ``get_prob_dist`` and ``get_prob_dist_using_survival_curve``, which + evaluate a single model component at a time, this function evaluates the + composed prediction for one or more services — multiple flows (ED current, + yet-to-arrive, transfers, departures) convolved together via + ``DemandPredictor``. + + ``build_service_data`` is called once per snapshot date and produces + ``ServicePredictionInputs`` for *all* specialties simultaneously, so + requesting multiple services adds negligible cost. + + For each snapshot date, this function: + + 1. Extracts the ED and (optionally) inpatient snapshots for the given + ``prediction_time``. + 2. Calls ``build_service_data`` to produce ``ServicePredictionInputs`` + for all specialties. + 3. Runs ``DemandPredictor.predict_service`` with the given + ``flow_selection`` for each requested service. + 4. Counts the observed admissions from the data for each service. + 5. Packages the predicted PMF and observed count into the standard + evaluation dictionary format consumed by ``plot_epudd``, + ``plot_randomised_pit``, ``qq_plot``, etc. + + Parameters + ---------- + ed_visits : pd.DataFrame + Full ED visits dataframe (all dates, all prediction times). Must + contain columns ``snapshot_date``, ``prediction_time``, + ``is_admitted``, ``specialty``, and ``elapsed_los`` (as timedelta). + snapshot_dates : List[date] + Dates in the test set to evaluate. + prediction_time : Tuple[int, int] + ``(hour, minute)`` of the prediction moment. + models : tuple + Seven-element tuple of trained models (or ``None``), as expected by + ``build_service_data``: ``(ed_classifier, inpatient_classifier, + spec_model, yta_model, non_ed_yta_model, elective_yta_model, + transfer_model)``. + specialties : List[str] + All specialties to pass to ``build_service_data``. This determines + the full set of ``ServicePredictionInputs`` that are prepared. + prediction_window : timedelta + Prediction horizon. + x1, y1, x2, y2 : float + Parameters for the admission-in-window probability curve. + services : List[str], optional + Which services to evaluate and return results for. Each must be + present in *specialties*. If ``None``, all *specialties* are + evaluated. + inpatient_visits : pd.DataFrame, optional + Full inpatient visits dataframe (all dates, all prediction times). + If provided, must contain columns ``snapshot_date``, + ``prediction_time``, and ``elapsed_los`` (as timedelta). Used + to supply inpatient snapshots for departure predictions. If + ``None``, departures are predicted as zero. + flow_selection : FlowSelection, optional + Which flows to include in the prediction. If ``None``, + ``FlowSelection.default()`` is used. + component : str, default ``"arrivals"`` + Which component of the ``PredictionBundle`` to extract for + evaluation. One of ``"arrivals"``, ``"departures"``, or + ``"net_flow"``. + verbose : bool, default ``False`` + If ``True``, print a one-line summary on completion. + + Returns + ------- + Dict[str, Dict[date, Dict[str, Any]]] + Dictionary mapping each service name to a dict mapping each + snapshot date to a dict with keys ``'agg_predicted'`` (DataFrame + with ``'agg_proba'`` column) and ``'agg_observed'`` (int). The + inner dict is the standard format expected by the evaluation + visualisation functions. + + Raises + ------ + ValueError + If ``component`` is not one of the recognised values, or + if any entry in *services* is not found in *specialties*. + """ + from patientflow.predict.service import build_service_data + from patientflow.predict.demand import DemandPredictor, FlowSelection + + valid_components = ("arrivals", "departures", "net_flow") + if component not in valid_components: + raise ValueError( + f"component must be one of {valid_components}, " f"got '{component}'" + ) + + if services is None: + services = list(specialties) + else: + unknown = [s for s in services if s not in specialties] + if unknown: + raise ValueError( + f"services {unknown} not found in specialties {specialties}" + ) + + if flow_selection is None: + flow_selection = FlowSelection.default() + + predictor = DemandPredictor(k_sigma=8.0) + result: Dict[str, Dict[date, Dict[str, Any]]] = {svc: {} for svc in services} + + for dt in snapshot_dates: + ed_snapshot = ed_visits[ + (ed_visits["snapshot_date"] == dt) + & (ed_visits["prediction_time"] == prediction_time) + ] + + if ed_snapshot.empty: + for svc in services: + result[svc][dt] = prediction_to_eval_dict(np.array([1.0]), observed=0) + continue + + ed_snapshot_processed = ed_snapshot.copy(deep=True) + if not pd.api.types.is_timedelta64_dtype(ed_snapshot_processed["elapsed_los"]): + ed_snapshot_processed["elapsed_los"] = pd.to_timedelta( + ed_snapshot_processed["elapsed_los"], unit="s" + ) + + inpatient_snapshot = None + if inpatient_visits is not None: + ip_mask = (inpatient_visits["snapshot_date"] == dt) & ( + inpatient_visits["prediction_time"] == prediction_time + ) + ip_filtered = inpatient_visits[ip_mask] + if not ip_filtered.empty: + inpatient_snapshot = ip_filtered.copy(deep=True) + if not pd.api.types.is_timedelta64_dtype( + inpatient_snapshot["elapsed_los"] + ): + inpatient_snapshot["elapsed_los"] = pd.to_timedelta( + inpatient_snapshot["elapsed_los"], unit="s" + ) + + service_data = build_service_data( + models=models, + prediction_time=prediction_time, + ed_snapshots=ed_snapshot_processed, + inpatient_snapshots=inpatient_snapshot, + specialties=specialties, + prediction_window=prediction_window, + x1=x1, + y1=y1, + x2=x2, + y2=y2, + ) + + for svc in services: + bundle = predictor.predict_service( + inputs=service_data[svc], + flow_selection=flow_selection, + ) + + demand_prediction = getattr(bundle, component) + + observed = _count_observed_admissions( + ed_visits, + dt, + prediction_time, + prediction_window, + specialty=svc, + ) + + result[svc][dt] = prediction_to_eval_dict( + demand_prediction.probabilities, observed + ) + + if verbose: + print( + f"prediction_time={prediction_time}: " + f"{len(services)} services × {len(snapshot_dates)} dates" + ) + + return result diff --git a/src/patientflow/predict/demand.py b/src/patientflow/predict/demand.py index 1d52f64..2e17fdf 100644 --- a/src/patientflow/predict/demand.py +++ b/src/patientflow/predict/demand.py @@ -136,6 +136,7 @@ def inflow_allowed(key: str) -> bool: ) selected_inflows = [inputs.inflows[k] for k in inflow_keys if inflow_allowed(k)] + is_aspirational = any(flow.aspirational for flow in selected_inflows) arrivals = self.predict_flow_total(selected_inflows, service_id, "arrivals") # Build outflows from families and cohort @@ -210,6 +211,7 @@ def outflow_allowed(key: str) -> bool: departures=departures, net_flow=net_flow, flow_selection=flow_selection, + is_aspirational=is_aspirational, ) def predict_flow_total( @@ -375,6 +377,8 @@ def _create_bundle_from_children( else FlowSelection.default() ) + is_aspirational = any(b.is_aspirational for b in child_bundles) + return PredictionBundle( entity_id=entity_id, entity_type=entity_type, @@ -382,6 +386,7 @@ def _create_bundle_from_children( departures=departures, net_flow=net_flow, flow_selection=flow_selection, + is_aspirational=is_aspirational, ) def convolve_multiple( diff --git a/src/patientflow/predict/emergency_demand.py b/src/patientflow/predict/emergency_demand.py index 7fdaef8..6cfe0b2 100644 --- a/src/patientflow/predict/emergency_demand.py +++ b/src/patientflow/predict/emergency_demand.py @@ -49,13 +49,52 @@ EmpiricalIncomingAdmissionPredictor, ) from patientflow.model_artifacts import TrainedClassifier -from patientflow.predict.validation import warn_specialty_mismatch # SettingWithCopyWarning was removed in pandas 3.0 (CoW is now default) if hasattr(pd.errors, "SettingWithCopyWarning"): warnings.filterwarnings("ignore", category=pd.errors.SettingWithCopyWarning) +def warn_specialty_mismatch( + requested: set, + trained: set, + source_label: str, + *, + stacklevel: int = 3, +) -> None: + """Emit warnings when requested and trained specialty sets diverge. + + Parameters + ---------- + requested : set + Specialties coming from the current request (e.g. Clarity). + trained : set + Specialties the model was trained on. + source_label : str + Human-readable name for the trained artefact, used in messages + (e.g. ``"yet-to-arrive model"`` or ``"special_category_dict"``). + stacklevel : int, optional + Passed to :func:`warnings.warn` so the warning points to the + caller rather than this helper. Default is 3 (caller's caller). + """ + new_in_request = requested - trained + missing_from_request = trained - requested + if new_in_request: + warnings.warn( + f"{len(new_in_request)} specialties found in the request but absent " + f"from the trained {source_label} (models may need retraining): " + f"{sorted(new_in_request)}", + stacklevel=stacklevel, + ) + if missing_from_request: + warnings.warn( + f"{len(missing_from_request)} specialties present in the trained " + f"{source_label} but absent from the request: " + f"{sorted(missing_from_request)}", + stacklevel=stacklevel, + ) + + def add_missing_columns(pipeline, df): """Add missing columns required by the prediction pipeline from the training data. @@ -436,6 +475,8 @@ def create_predictions( "special_category_dict", ) + trained_yta_keys = set(yet_to_arrive_model.filters.keys()) + predictions: Dict[str, Dict[str, Any]] = { specialty: {"in_ed": [], "yet_to_arrive": []} for specialty in specialties } @@ -555,10 +596,14 @@ def create_predictions( filtered_prob_admission_after_ed, weights=filtered_weights ) - prediction_context = {specialty: {"prediction_time": prediction_time}} - agg_predicted_yta = yet_to_arrive_model.predict( - prediction_context, x1=x1, y1=y1, x2=x2, y2=y2 - ) + if specialty in trained_yta_keys: + prediction_context = {specialty: {"prediction_time": prediction_time}} + agg_predicted_yta = yet_to_arrive_model.predict( + prediction_context, x1=x1, y1=y1, x2=x2, y2=y2 + ) + yta_proba = agg_predicted_yta[specialty]["agg_proba"] + else: + yta_proba = pd.Series([1.0], name="agg_proba") if cdf_cut_points is not None: predictions[specialty]["in_ed"] = [ @@ -568,15 +613,11 @@ def create_predictions( for cut_point in cdf_cut_points ] predictions[specialty]["yet_to_arrive"] = [ - find_probability_threshold_index( - agg_predicted_yta[specialty]["agg_proba"].values, cut_point - ) + find_probability_threshold_index(yta_proba.values, cut_point) for cut_point in cdf_cut_points ] else: predictions[specialty]["in_ed"] = agg_predicted_in_ed["agg_proba"] - predictions[specialty]["yet_to_arrive"] = agg_predicted_yta[specialty][ - "agg_proba" - ] + predictions[specialty]["yet_to_arrive"] = yta_proba return predictions diff --git a/src/patientflow/predict/service.py b/src/patientflow/predict/service.py index b9dc604..35ed446 100644 --- a/src/patientflow/predict/service.py +++ b/src/patientflow/predict/service.py @@ -22,8 +22,8 @@ from patientflow.predict.emergency_demand import ( add_missing_columns, get_specialty_probs, + warn_specialty_mismatch, ) -from patientflow.predict.validation import warn_specialty_mismatch from patientflow.predictors.incoming_admission_predictors import ( ParametricIncomingAdmissionPredictor, EmpiricalIncomingAdmissionPredictor, @@ -97,6 +97,7 @@ class FlowInputs: flow_type: str distribution: Union[np.ndarray, float] display_name: Optional[str] = None + aspirational: bool = False def get_display_name(self) -> str: """Get human-readable display name. @@ -459,7 +460,7 @@ def _validate_models_and_data( "and ED snapshots are provided, but spec_model is None" ) - # Validate specialties alignment + # Validate specialties alignment (warn only — filtering happens at call sites) if yet_to_arrive_model is not None and hasattr(yet_to_arrive_model, "filters"): warn_specialty_mismatch( set(specialties), @@ -849,6 +850,14 @@ def _create_flow_inputs( """ prediction_context = {spec: {"prediction_time": prediction_time}} + def _safe_predict_mean(model, context, **kwargs) -> float: + # Return 0.0 when the model is None or doesn't recognise the filter key + if model is None: + return 0.0 + if hasattr(model, "weights") and spec not in model.weights: + return 0.0 + return float(model.predict_mean(context, **kwargs)) + # Build FlowInputs objects for inflows and outflows # INFLOWS: All sources of patient arrivals to this subspecialty inflows_dict = { @@ -861,33 +870,24 @@ def _create_flow_inputs( "ed_yta": FlowInputs( flow_id="ed_yta", flow_type="poisson", - distribution=float( - yet_to_arrive_model.predict_mean( - prediction_context, x1=x1, y1=y1, x2=x2, y2=y2 - ) - if yet_to_arrive_model is not None - else 0.0 + distribution=_safe_predict_mean( + yet_to_arrive_model, prediction_context, x1=x1, y1=y1, x2=x2, y2=y2 ), display_name="ED yet-to-arrive admissions", + aspirational=isinstance( + yet_to_arrive_model, ParametricIncomingAdmissionPredictor + ), ), "non_ed_yta": FlowInputs( flow_id="non_ed_yta", flow_type="poisson", - distribution=float( - non_ed_yta_model.predict_mean(prediction_context) - if non_ed_yta_model is not None - else 0.0 - ), + distribution=_safe_predict_mean(non_ed_yta_model, prediction_context), display_name="Non-ED emergency admissions", ), "elective_yta": FlowInputs( flow_id="elective_yta", flow_type="poisson", - distribution=float( - elective_yta_model.predict_mean(prediction_context) - if elective_yta_model is not None - else 0.0 - ), + distribution=_safe_predict_mean(elective_yta_model, prediction_context), display_name="Elective admissions", ), # Note: "transfers_in" will be added later after compute_transfer_arrivals() diff --git a/src/patientflow/predict/types.py b/src/patientflow/predict/types.py index f2aa012..421ebfd 100644 --- a/src/patientflow/predict/types.py +++ b/src/patientflow/predict/types.py @@ -291,6 +291,11 @@ class PredictionBundle: Selection specifying which flow families and cohort were included in this prediction. Tracks which inflows and outflows were aggregated into the arrivals and departures distributions. + is_aspirational : bool + True if any inflow contributing to this prediction was generated under + aspirational assumptions (e.g. ED performance targets) rather than from + empirically observed patterns. When True, comparisons against observed + admission counts may not be valid. Notes ----- @@ -309,6 +314,7 @@ class PredictionBundle: departures: DemandPrediction net_flow: DemandPrediction flow_selection: FlowSelection + is_aspirational: bool = False def to_summary(self) -> Dict[str, Any]: """Return human-readable summary of predictions. @@ -376,8 +382,9 @@ def format_pmf( def __str__(self) -> str: summary = self.to_summary() + tag = " [aspirational]" if self.is_aspirational else "" return ( - f"PredictionBundle({summary['entity']})\n" + f"PredictionBundle({summary['entity']}){tag}\n" f" {'Arrivals:':<12} {summary['arrivals_pmf']}\n" f" {'Departures:':<12} {summary['departures_pmf']}\n" f" {'Net flow:':<12} {summary['net_flow_pmf']}\n" diff --git a/src/patientflow/predict/validation.py b/src/patientflow/predict/validation.py deleted file mode 100644 index cc41550..0000000 --- a/src/patientflow/predict/validation.py +++ /dev/null @@ -1,43 +0,0 @@ -"""Validation helpers for the predict package.""" - -import warnings - - -def warn_specialty_mismatch( - requested: set, - trained: set, - source_label: str, - *, - stacklevel: int = 3, -) -> None: - """Emit warnings when requested and trained specialty sets diverge. - - Parameters - ---------- - requested : set - Specialties coming from the current request (e.g. Clarity). - trained : set - Specialties the model was trained on. - source_label : str - Human-readable name for the trained artefact, used in messages - (e.g. ``"yet-to-arrive model"`` or ``"special_category_dict"``). - stacklevel : int, optional - Passed to :func:`warnings.warn` so the warning points to the - caller rather than this helper. Default is 3 (caller's caller). - """ - new_in_request = requested - trained - missing_from_request = trained - requested - if new_in_request: - warnings.warn( - f"{len(new_in_request)} specialties found in the request but absent " - f"from the trained {source_label} (models may need retraining): " - f"{sorted(new_in_request)}", - stacklevel=stacklevel, - ) - if missing_from_request: - warnings.warn( - f"{len(missing_from_request)} specialties present in the trained " - f"{source_label} but absent from the request: " - f"{sorted(missing_from_request)}", - stacklevel=stacklevel, - ) diff --git a/src/patientflow/viz/pipeline_plots.py b/src/patientflow/viz/pipeline_plots.py index d8261e3..f2d1c2c 100644 --- a/src/patientflow/viz/pipeline_plots.py +++ b/src/patientflow/viz/pipeline_plots.py @@ -333,6 +333,7 @@ def in_ed_now_plot( colour=False, text_size=None, jitter_amount=0.1, + jitter_offsets=None, size=50, preds_col="preds", colour_map="Spectral_r", @@ -374,6 +375,11 @@ def in_ed_now_plot( Font size for tick labels and (if shown) titles. jitter_amount : float, optional Vertical jitter applied to dots. Default ``0.1``. + jitter_offsets : pandas.Series or dict or None, optional + Precomputed per-row jitter values keyed by ``ex.index``. When + provided, these values are used instead of generating fresh random + jitter, which allows consistent vertical offsets across multiple + related plots. Default ``None``. size : int, optional Marker size. Default ``50``. preds_col : str, optional @@ -419,9 +425,18 @@ def in_ed_now_plot( else: fig, target_ax = plt.subplots(figsize=(figsize_x, figsize_y)) for location, group in ex.groupby("loc_new", observed=True): - jittered_y = loc_to_num[location] + np.random.uniform( - -jitter_amount, jitter_amount, size=len(group) - ) + if jitter_offsets is None: + offsets = np.random.uniform( + -jitter_amount, jitter_amount, size=len(group) + ) + else: + if isinstance(jitter_offsets, pd.Series): + offsets = jitter_offsets.reindex(group.index).fillna(0.0).to_numpy() + else: + offsets = np.array( + [jitter_offsets.get(i, 0.0) for i in group.index] + ) + jittered_y = loc_to_num[location] + offsets target_ax.scatter( group["elapsed_los"] / 3600, jittered_y, @@ -444,9 +459,18 @@ def in_ed_now_plot( else: fig, target_ax = plt.subplots(figsize=(figsize_x - 1, figsize_y)) for location, group in ex.groupby("loc_new", observed=True): - jittered_y = loc_to_num[location] + np.random.uniform( - -jitter_amount, jitter_amount, size=len(group) - ) + if jitter_offsets is None: + offsets = np.random.uniform( + -jitter_amount, jitter_amount, size=len(group) + ) + else: + if isinstance(jitter_offsets, pd.Series): + offsets = jitter_offsets.reindex(group.index).fillna(0.0).to_numpy() + else: + offsets = np.array( + [jitter_offsets.get(i, 0.0) for i in group.index] + ) + jittered_y = loc_to_num[location] + offsets target_ax.scatter( group["elapsed_los"] / 3600, jittered_y, @@ -618,6 +642,11 @@ def main( ) prediction_window = timedelta(minutes=config["prediction_window"]) plot_order = ["medical", "surgical", "haem/onc", "paediatric"] + # Keep patient vertical jitter consistent across all scatter figures. + shared_jitter = pd.Series( + np.random.uniform(-0.1, 0.1, size=len(ex)), + index=ex.index, + ) # ------------------------------------------------------------------ # Figure (a) – patients in ED, no colour @@ -627,6 +656,7 @@ def main( title=title_base, include_titles=include_titles, return_figure=True, + jitter_offsets=shared_jitter, ) _save_fig(fig_a, save_dir, "figure_a_patients_in_ed.png", "a") @@ -654,6 +684,7 @@ def main( colour_map="Spectral_r", include_titles=include_titles, return_figure=True, + jitter_offsets=shared_jitter, ) _save_fig(fig_b, save_dir, "figure_b_admission_probability.png", "b") @@ -695,17 +726,23 @@ def main( specialty_model=prediction_inputs["specialty_model"], specialties=prediction_inputs["specialties"], ) - fig_e, axes_e = plt.subplots(2, 2, figsize=(12, 8)) for ax, specialty in zip(axes_e.flat, plot_order): + ex_with_specialty["_specialty_plot_prob"] = ex_with_specialty[ + "specialty_prob" + ].apply( + lambda probs: probs.get(specialty, 0.0) if isinstance(probs, dict) else 0.0 + ) in_ed_now_plot( ex_with_specialty, title=specialty.title(), colour=True, colour_map=spec_colour_dict["spectrum"].get(specialty, "Spectral_r"), + preds_col="_specialty_plot_prob", include_titles=include_titles, ax=ax, text_size=14, + jitter_offsets=shared_jitter, ) if include_titles: fig_e.suptitle( @@ -713,7 +750,7 @@ def main( fontsize=16, ) fig_e.tight_layout() - _save_fig(fig_e, save_dir, "figure_e_specialty_scatter.png", "e") + _save_fig(fig_e, save_dir, "figure_e_specialty_of_admission.png", "e") # ------------------------------------------------------------------ # Figure (f) – per-specialty bed demand (no admission-in-window prob) @@ -803,6 +840,7 @@ def main( preds_col="prob_adm_in_window", include_titles=include_titles, return_figure=True, + jitter_offsets=shared_jitter, ) _save_fig(fig_h, save_dir, "figure_h_admission_in_window.png", "h")