{ "cells": [ { "cell_type": "markdown", "id": "01e1fbaf-a767-4a87-98ea-11a0a125b0d0", "metadata": {}, "source": [ "# Demo: Continuous outcome model\n", "\n", "This notebook contains a basic example of running the continuous outcome model within the `stroke-outcome` package." ] }, { "cell_type": "markdown", "id": "add8e9e5-611e-4749-8d15-ac2aa21f54a1", "metadata": {}, "source": [ "## Notebook setup\n", "\n", "The intended versions of these packages are given in the files `environment.yml` and `requirements.txt`." ] }, { "cell_type": "code", "execution_count": 1, "id": "3460e723-efc0-4f70-9c32-a807af96ce85", "metadata": {}, "outputs": [], "source": [ "# Import required packages\n", "import numpy as np\n", "import pandas as pd\n", "import copy\n", "\n", "# Imports from the stroke_outcome package:\n", "from stroke_outcome.continuous_outcome import Continuous_outcome\n", "import stroke_outcome.outcome_utilities as outcome_utilities" ] }, { "cell_type": "markdown", "id": "defe25ab-a29f-4758-8db7-655aaf3e5a1a", "metadata": {}, "source": [ "## Create patient data\n", "\n", "The model needs the following data as inputs, with one value per patient in each array:\n", "\n", "| Data | Units | Data type | Name |\n", "| --- | --- | --- | --- |\n", "| Stroke type code | 0=other, 1=nLVO, 2=LVO | int | `stroke_type_code` |\n", "| Onset to needle time | minutes | float | `onset_to_needle_mins` |\n", "| Whether IVT was chosen | 1=True, 0=False | int or bool | `ivt_chosen_bool` |\n", "| Onset to puncture time | minutes | float | `onset_to_puncture_mins` |\n", "| Whether MT was chosen | 1=True, 0=False | int or bool | `mt_chosen_bool` |\n", "\n", "These are expected in a dictionary (or a pandas DataFrame? check this). For example:" ] }, { "cell_type": "code", "execution_count": 2, "id": "dec529de-e40d-4446-8248-3a706e77bb6d", "metadata": {}, "outputs": [], "source": [ "# Set random seed for repeatability:\n", "np.random.seed(42)\n", "\n", "# All patients share these same treatment times:\n", "time_to_ivt_mins = 90.0\n", "time_to_mt_mins = 120.0\n", "\n", "# Numbers of patients with each stroke type:\n", "n_nlvo = 65\n", "n_lvo = 35\n", "n_total = n_lvo + n_nlvo\n", "\n", "# Store the patient details in this dictionary:\n", "outcome_inputs_dict = dict(\n", " # Mix of LVO and nLVO:\n", " stroke_type_code=np.array([2]*n_lvo + [1]*n_nlvo),\n", " # Onset to needle time is fixed to 90mins:\n", " onset_to_needle_mins=np.full(n_total, time_to_ivt_mins),\n", " # Randomly pick whether IVT is chosen with around 15% yes: \n", " ivt_chosen_bool=np.random.binomial(1, 0.15, n_total) == 1,\n", " # Onset to puncture time is fixed to 120mins:\n", " onset_to_puncture_mins=np.full(n_total, time_to_mt_mins),\n", " # Randomly pick whether MT is chosen for LVOs with around 30% yes:\n", " mt_chosen_bool=np.concatenate(\n", " (np.random.binomial(1, 0.3, n_lvo), [0]*n_nlvo)) == 1\n", ")" ] }, { "cell_type": "markdown", "id": "73c8373e-deb0-4bb8-af7e-f53584fe81ab", "metadata": {}, "source": [ "Convert this to a DataFrame for easier viewing:" ] }, { "cell_type": "code", "execution_count": 3, "id": "193e29e1-db09-4308-8d98-717ec4cdd024", "metadata": {}, "outputs": [ { "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", " \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", "
0123456789
stroke_type_code2.02.02.02.02.02.02.02.02.02.0
onset_to_needle_mins90.090.090.090.090.090.090.090.090.090.0
ivt_chosen_bool0.01.00.00.00.00.00.01.00.00.0
onset_to_puncture_mins120.0120.0120.0120.0120.0120.0120.0120.0120.0120.0
mt_chosen_bool0.00.00.00.01.00.00.01.00.00.0
\n", "
" ], "text/plain": [ " 0 1 2 3 4 5 6 \\\n", "stroke_type_code 2.0 2.0 2.0 2.0 2.0 2.0 2.0 \n", "onset_to_needle_mins 90.0 90.0 90.0 90.0 90.0 90.0 90.0 \n", "ivt_chosen_bool 0.0 1.0 0.0 0.0 0.0 0.0 0.0 \n", "onset_to_puncture_mins 120.0 120.0 120.0 120.0 120.0 120.0 120.0 \n", "mt_chosen_bool 0.0 0.0 0.0 0.0 1.0 0.0 0.0 \n", "\n", " 7 8 9 \n", "stroke_type_code 2.0 2.0 2.0 \n", "onset_to_needle_mins 90.0 90.0 90.0 \n", "ivt_chosen_bool 1.0 0.0 0.0 \n", "onset_to_puncture_mins 120.0 120.0 120.0 \n", "mt_chosen_bool 1.0 0.0 0.0 " ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Pop them into a dataframe:\n", "outcome_inputs_df = pd.DataFrame(\n", " np.array(list(outcome_inputs_dict.values())).T,#, dtype=object).T,\n", " columns=outcome_inputs_dict.keys(),\n", ")\n", "\n", "# Show the first ten patients' details:\n", "outcome_inputs_df.head(10).T" ] }, { "cell_type": "markdown", "id": "e407bb3e-99e4-4cf4-b057-c0d295424514", "metadata": {}, "source": [ "Note: even though all patients here have valid treatment times, the model only uses the times for patients who answer `True` in the treatment chosen arrays." ] }, { "cell_type": "markdown", "id": "4c48c234-5938-4afc-a3d4-ed74c25f79cc", "metadata": {}, "source": [ "## Alternative: Import data from file" ] }, { "cell_type": "code", "execution_count": 4, "id": "7f3aa43a-c320-4a61-a817-60a2d2633792", "metadata": {}, "outputs": [], "source": [ "outcome_inputs_df = pd.read_csv('patients.csv')" ] }, { "cell_type": "code", "execution_count": 5, "id": "38911909-848b-45fe-9d1c-4879f5795b54", "metadata": { "scrolled": true }, "outputs": [ { "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", " \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", "
012345678910111213
stroke_type_code11111112222222
onset_to_needle_mins0037800037800378000378
ivt_chosen_bool01100110110011
onset_to_puncture_mins0000480048000004800480
mt_chosen_bool00011110001111
\n", "
" ], "text/plain": [ " 0 1 2 3 4 5 6 7 8 9 10 11 \\\n", "stroke_type_code 1 1 1 1 1 1 1 2 2 2 2 2 \n", "onset_to_needle_mins 0 0 378 0 0 0 378 0 0 378 0 0 \n", "ivt_chosen_bool 0 1 1 0 0 1 1 0 1 1 0 0 \n", "onset_to_puncture_mins 0 0 0 0 480 0 480 0 0 0 0 480 \n", "mt_chosen_bool 0 0 0 1 1 1 1 0 0 0 1 1 \n", "\n", " 12 13 \n", "stroke_type_code 2 2 \n", "onset_to_needle_mins 0 378 \n", "ivt_chosen_bool 1 1 \n", "onset_to_puncture_mins 0 480 \n", "mt_chosen_bool 1 1 " ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "outcome_inputs_df.T" ] }, { "cell_type": "markdown", "id": "0ceb9a20-2b1f-4143-bf1c-96dadc21cd2d", "metadata": {}, "source": [ "## Run the continuous outcome model\n", "\n", "Initiate the outcome model object:" ] }, { "cell_type": "code", "execution_count": 6, "id": "99f8086a-d5f2-4036-9cb9-843f3a60404c", "metadata": {}, "outputs": [], "source": [ "continuous_outcome = Continuous_outcome()" ] }, { "cell_type": "markdown", "id": "a92e24e3-ca8d-4457-ad3c-5408c18f615b", "metadata": {}, "source": [ "Provide it with the data we created above:" ] }, { "cell_type": "code", "execution_count": 7, "id": "e6af7b52-7864-4302-97de-edba51541ac1", "metadata": {}, "outputs": [], "source": [ "continuous_outcome.assign_patients_to_trial(outcome_inputs_df)" ] }, { "cell_type": "markdown", "id": "43494890-12f2-4ba9-8cdf-8b8563610fa0", "metadata": {}, "source": [ "The model is expecting to receive patient data for some of the keys in the `trial` dictionary:" ] }, { "cell_type": "code", "execution_count": 8, "id": "34bb32e2-2020-4c3e-bb1c-5558315624af", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "stroke_type_code\n", "stroke_type_code_on_input\n", "onset_to_needle_mins\n", "ivt_chosen_bool\n", "ivt_no_effect_bool\n", "onset_to_puncture_mins\n", "mt_chosen_bool\n", "mt_no_effect_bool\n" ] } ], "source": [ "for key in continuous_outcome.trial.keys():\n", " print(key)" ] }, { "cell_type": "markdown", "id": "3e95b925-f05e-4e6e-b170-cd1e7a7a48af", "metadata": {}, "source": [ "We don't need to define `ivt_no_effect_bool` and `mt_no_effect_bool` because they are created when the outcomes are calculated. Those two arrays record whether each patient was treated after the time of no effect." ] }, { "cell_type": "code", "execution_count": 9, "id": "49cbfdfc-781f-4849-8de3-d89dfcfea636", "metadata": {}, "outputs": [], "source": [ "# Calculate outcomes:\n", "patient_data_dict, outcomes_by_stroke_type, full_cohort_outcomes = (\n", " continuous_outcome.calculate_outcomes())\n", "\n", "# Make a copy of the results:\n", "outcomes_by_stroke_type = copy.copy(outcomes_by_stroke_type)\n", "full_cohort_outcomes = copy.copy(full_cohort_outcomes)" ] }, { "attachments": {}, "cell_type": "markdown", "id": "5ea3dbca-b8bf-4b04-9820-644a4980cbeb", "metadata": {}, "source": [ "Notes: \n", "+ A copy is made of the output results as currently the original results can be overwritten when a new instance of the `Continuous_outcome` class is created.\n", "\n", "The model also produces statistics about the input patient population:" ] }, { "cell_type": "code", "execution_count": 10, "id": "05940302-756f-4af1-9dcf-cf4b3bba74d0", "metadata": {}, "outputs": [ { "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", " \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", "
TotalIVTMTIVT no effectMT no effectNo treatment
nLVO: Count3.0000002.0000000.0000001.0000000.0000001.000000
nLVO: Proportion of this stroke type1.0000000.6666670.0000000.3333330.0000000.333333
nLVO: Proportion of full cohort0.2142860.1428570.0000000.0714290.0000000.071429
LVO: Count11.0000006.0000008.0000003.0000004.0000001.000000
LVO: Proportion of this stroke type1.0000000.5454550.7272730.2727270.3636360.090909
LVO: Proportion of full cohort0.7857140.4285710.5714290.2142860.2857140.071429
Other: Count0.0000000.0000000.0000000.0000000.0000000.000000
Other: Proportion of this stroke type1.000000NaNNaNNaNNaNNaN
Other: Proportion of full cohort0.0000000.0000000.0000000.0000000.0000000.000000
\n", "
" ], "text/plain": [ " Total IVT MT \\\n", "nLVO: Count 3.000000 2.000000 0.000000 \n", "nLVO: Proportion of this stroke type 1.000000 0.666667 0.000000 \n", "nLVO: Proportion of full cohort 0.214286 0.142857 0.000000 \n", "LVO: Count 11.000000 6.000000 8.000000 \n", "LVO: Proportion of this stroke type 1.000000 0.545455 0.727273 \n", "LVO: Proportion of full cohort 0.785714 0.428571 0.571429 \n", "Other: Count 0.000000 0.000000 0.000000 \n", "Other: Proportion of this stroke type 1.000000 NaN NaN \n", "Other: Proportion of full cohort 0.000000 0.000000 0.000000 \n", "\n", " IVT no effect MT no effect \\\n", "nLVO: Count 1.000000 0.000000 \n", "nLVO: Proportion of this stroke type 0.333333 0.000000 \n", "nLVO: Proportion of full cohort 0.071429 0.000000 \n", "LVO: Count 3.000000 4.000000 \n", "LVO: Proportion of this stroke type 0.272727 0.363636 \n", "LVO: Proportion of full cohort 0.214286 0.285714 \n", "Other: Count 0.000000 0.000000 \n", "Other: Proportion of this stroke type NaN NaN \n", "Other: Proportion of full cohort 0.000000 0.000000 \n", "\n", " No treatment \n", "nLVO: Count 1.000000 \n", "nLVO: Proportion of this stroke type 0.333333 \n", "nLVO: Proportion of full cohort 0.071429 \n", "LVO: Count 1.000000 \n", "LVO: Proportion of this stroke type 0.090909 \n", "LVO: Proportion of full cohort 0.071429 \n", "Other: Count 0.000000 \n", "Other: Proportion of this stroke type NaN \n", "Other: Proportion of full cohort 0.000000 " ] }, "execution_count": 10, "metadata": {}, "output_type": "execute_result" } ], "source": [ "continuous_outcome.stroke_type_stats_df.T" ] }, { "cell_type": "markdown", "id": "c961f0d8-cdfa-4fdc-be8a-a8bc83183e39", "metadata": { "tags": [] }, "source": [ "## Results\n", "\n", "The main function returns three sets of results, which we've called `patient_data_dict`, `outcomes_by_stroke_type` and `full_cohort_outcomes`. \n", "\n", "The first result is a dictionary of the input patient information. This is important for two reasons. Firsly, if not all of the data required for the model was provided by the user, then the output dictionary shows a record of the placeholder data that was used instead. Usually the placeholder data is all zeroes. Secondly, in special cases the input patient data is overwritten. The main special case is patients who have an nLVO and are given MT, where the model updates this so that they are assigned as LVO instead.\n", "\n", "The other two are dictionaries and hold similar information. The important difference is that `outcomes_by_stroke_type` contains separate information for each occlusion and treatment type, and that `full_cohort_outcomes` contains one set of information that matches the input patient types.\n", "\n", "The output patient data dictionary contains the following:" ] }, { "cell_type": "code", "execution_count": 11, "id": "65d3103a-4f61-4bdc-8fbd-e5d5df6f9a30", "metadata": {}, "outputs": [ { "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", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \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", "
012345678910111213
stroke_type_code11122222222222
stroke_type_code_on_input11111112222222
onset_to_needle_mins0037800037800378000378
ivt_chosen_bool01100110110011
ivt_no_effect_boolFalseFalseTrueFalseFalseFalseTrueFalseFalseTrueFalseFalseFalseTrue
onset_to_puncture_mins0000480048000004800480
mt_chosen_bool00011110001111
mt_no_effect_boolFalseFalseFalseFalseTrueFalseTrueFalseFalseFalseFalseTrueFalseTrue
\n", "
" ], "text/plain": [ " 0 1 2 3 4 5 6 \\\n", "stroke_type_code 1 1 1 2 2 2 2 \n", "stroke_type_code_on_input 1 1 1 1 1 1 1 \n", "onset_to_needle_mins 0 0 378 0 0 0 378 \n", "ivt_chosen_bool 0 1 1 0 0 1 1 \n", "ivt_no_effect_bool False False True False False False True \n", "onset_to_puncture_mins 0 0 0 0 480 0 480 \n", "mt_chosen_bool 0 0 0 1 1 1 1 \n", "mt_no_effect_bool False False False False True False True \n", "\n", " 7 8 9 10 11 12 13 \n", "stroke_type_code 2 2 2 2 2 2 2 \n", "stroke_type_code_on_input 2 2 2 2 2 2 2 \n", "onset_to_needle_mins 0 0 378 0 0 0 378 \n", "ivt_chosen_bool 0 1 1 0 0 1 1 \n", "ivt_no_effect_bool False False True False False False True \n", "onset_to_puncture_mins 0 0 0 0 480 0 480 \n", "mt_chosen_bool 0 0 0 1 1 1 1 \n", "mt_no_effect_bool False False False False True False True " ] }, "execution_count": 11, "metadata": {}, "output_type": "execute_result" } ], "source": [ "pd.DataFrame(patient_data_dict.values(), patient_data_dict.keys())" ] }, { "cell_type": "markdown", "id": "78e04819-2a09-4147-928e-302bf0914762", "metadata": {}, "source": [ "`outcomes_by_stroke_type` contains the following keys for each of `lvo_ivt`, `lvo_mt`, and `nlvo_ivt`:" ] }, { "cell_type": "code", "execution_count": 12, "id": "5c3ace3f-a838-49ab-9433-93d1d945637d", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "+ each_patient_mrs_dist_post_stroke\n", "+ mrs_not_treated\n", "+ mrs_no_effect\n", "+ each_patient_mrs_post_stroke\n", "+ each_patient_mrs_shift\n", "+ utility_not_treated\n", "+ utility_no_effect\n", "+ each_patient_utility_post_stroke\n", "+ each_patient_utility_shift\n", "+ valid_patients_mean_mrs_shift\n", "+ valid_patients_mean_utility_shift\n", "+ treated_patients_mean_mrs_shift\n", "+ treated_patients_mean_utility_shift\n" ] } ], "source": [ "separate_keys = list(outcomes_by_stroke_type.keys())\n", "\n", "for key in separate_keys[:len(separate_keys)//3]:\n", " short_key = '_'.join(key.split('_')[2:]) # Remove lvo_ivt label\n", " print('+ ' + short_key) " ] }, { "cell_type": "markdown", "id": "e65a7d95-1736-4639-8e63-1205cca83a90", "metadata": {}, "source": [ "`full_cohort_outcomes` combines the three subgroups back into one big array in the same order as the input data. It contains:" ] }, { "cell_type": "code", "execution_count": 13, "id": "f9b8035f", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "+ each_patient_mrs_dist_post_stroke\n", "+ each_patient_mrs_post_stroke\n", "+ each_patient_mrs_shift\n", "+ each_patient_utility_post_stroke\n", "+ each_patient_utility_shift\n", "+ mean_mrs_post_stroke\n", "+ mean_mrs_shift\n", "+ mean_utility\n", "+ mean_utility_shift\n" ] } ], "source": [ "full_cohort_keys = list(full_cohort_outcomes.keys())\n", "\n", "for key in full_cohort_keys:\n", " print('+ ' + key)" ] }, { "attachments": {}, "cell_type": "markdown", "id": "399ef9e6-b562-4763-85ee-6e99418a84f0", "metadata": {}, "source": [ "### Example: mean mRS shift\n", "\n", "The mean mRS shift is stored in various different ways depending on what exactly you want to measure. In the separate subgroups, you can see the mean mRS shift for only the patients who were treated:" ] }, { "cell_type": "code", "execution_count": 14, "id": "32815524-728d-4856-942d-ec16d857dfa5", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "-0.425\n", "-0.190\n", "-0.651\n" ] } ], "source": [ "# Separate subgroup results:\n", "keys_to_print = [\n", " 'nlvo_ivt_treated_patients_mean_mrs_shift',\n", " 'lvo_ivt_treated_patients_mean_mrs_shift',\n", " 'lvo_mt_treated_patients_mean_mrs_shift',\n", "]\n", "for key in keys_to_print:\n", " print(f'{outcomes_by_stroke_type[key]:.3f}')" ] }, { "cell_type": "markdown", "id": "67ef79a2-6b4a-48f5-9189-b0a2d5171c0a", "metadata": {}, "source": [ "In the combined full cohort results, you can see the mean mRS shift for each patient separately:" ] }, { "cell_type": "code", "execution_count": 15, "id": "d49370f7-cc33-48eb-b90c-67fa18f6de37", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ 0. , -0.889, 0.039, -1.396, 0.093, -1.396, 0.083, 0. ,\n", " -0.464, 0.083, -1.396, 0.093, -1.396, 0.083])" ] }, "execution_count": 15, "metadata": {}, "output_type": "execute_result" } ], "source": [ "# Combined full cohort results:\n", "full_cohort_outcomes['each_patient_mrs_shift']" ] }, { "cell_type": "markdown", "id": "cf6d7cf0-9a3e-432a-bbeb-e77471864cca", "metadata": {}, "source": [ "There is also a full cohort mean mRS shift value..." ] }, { "cell_type": "code", "execution_count": 16, "id": "1c418f5f-0c32-476b-b506-25abd7055839", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "-0.462\n" ] } ], "source": [ "print(f\"{full_cohort_outcomes['mean_mrs_shift']:.3f}\")" ] }, { "attachments": {}, "cell_type": "markdown", "id": "87d6df18-d099-4136-864c-be337f803c80", "metadata": {}, "source": [ "... which is the mean of all values in the previous array including the zeroes. This might not be as useful a metric as the three separate mean mRS shifts from the nLVO+IVT, LVO+IVT, and LVO+MT subgroups.\n", "\n", "# Controlling mRS distributions and utility weightings\n", "\n", "The model contains datasets for mRS distributions and utility weights. These are automatically loaded and used in the model. If you want to use different data, you can provide it when you create the model.\n", "\n", "Custom times of no effect for thrombolysis and thrombectomy can be passed into the model. The default values match the mRS distributions imported from file.\n", "\n", "## Import reference data\n", "\n", "These functions import data from `.csv` files that are included in the `stroke-outcome` package. Each function imports both a copy of the data in the table and the notes in the header at the top of the file.\n", "\n", "__Data set 1:__ Cumulative probability distributions of modified Rankin scale (mRS):" ] }, { "cell_type": "code", "execution_count": 17, "id": "2dd0bbd4-644c-4b50-9797-1d435d128796", "metadata": {}, "outputs": [], "source": [ "mrs_dists, mrs_dists_notes = (\n", " outcome_utilities.import_mrs_dists_from_file())" ] }, { "cell_type": "code", "execution_count": 18, "id": "65781965-4849-4a17-ad74-a999999656b2", "metadata": {}, "outputs": [ { "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", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
mRS<=0mRS<=1mRS<=2mRS<=3mRS<=4mRS<=5mRS<=6
Stroke type
pre_stroke_nlvo0.5830.7460.8500.9510.9931.0001
pre_stroke_lvo0.4080.5520.6720.8380.9561.0001
no_treatment_lvo0.0500.1290.2650.4290.6760.8111
no_treatment_nlvo0.1980.4600.5800.7080.8560.9181
no_effect_nlvo_ivt_deaths0.1960.4550.5740.7010.8470.9081
no_effect_lvo_ivt_deaths0.0480.1240.2550.4140.6530.7831
no_effect_lvo_mt_deaths0.0480.1240.2550.4120.6490.7791
t0_treatment_nlvo_ivt0.4450.6420.7520.8620.9410.9671
t0_treatment_lvo_ivt0.1400.2330.3610.5220.7300.8381
t0_treatment_lvo_mt0.3060.4290.5480.7070.8510.9151
\n", "
" ], "text/plain": [ " mRS<=0 mRS<=1 mRS<=2 mRS<=3 mRS<=4 mRS<=5 \\\n", "Stroke type \n", "pre_stroke_nlvo 0.583 0.746 0.850 0.951 0.993 1.000 \n", "pre_stroke_lvo 0.408 0.552 0.672 0.838 0.956 1.000 \n", "no_treatment_lvo 0.050 0.129 0.265 0.429 0.676 0.811 \n", "no_treatment_nlvo 0.198 0.460 0.580 0.708 0.856 0.918 \n", "no_effect_nlvo_ivt_deaths 0.196 0.455 0.574 0.701 0.847 0.908 \n", "no_effect_lvo_ivt_deaths 0.048 0.124 0.255 0.414 0.653 0.783 \n", "no_effect_lvo_mt_deaths 0.048 0.124 0.255 0.412 0.649 0.779 \n", "t0_treatment_nlvo_ivt 0.445 0.642 0.752 0.862 0.941 0.967 \n", "t0_treatment_lvo_ivt 0.140 0.233 0.361 0.522 0.730 0.838 \n", "t0_treatment_lvo_mt 0.306 0.429 0.548 0.707 0.851 0.915 \n", "\n", " mRS<=6 \n", "Stroke type \n", "pre_stroke_nlvo 1 \n", "pre_stroke_lvo 1 \n", "no_treatment_lvo 1 \n", "no_treatment_nlvo 1 \n", "no_effect_nlvo_ivt_deaths 1 \n", "no_effect_lvo_ivt_deaths 1 \n", "no_effect_lvo_mt_deaths 1 \n", "t0_treatment_nlvo_ivt 1 \n", "t0_treatment_lvo_ivt 1 \n", "t0_treatment_lvo_mt 1 " ] }, "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ "mrs_dists" ] }, { "cell_type": "code", "execution_count": 19, "id": "8085b1aa-e436-43e7-8318-5c5db8bc61c0", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "# If these change, please ensure the no-effect times are still correct.,,,,,,\n", "#,,,,,,,\n", "# Acronyms: No-effect times:,,,,,,,\n", "# lvo: large-vessel occlusion IVT: 378mins (6.3hr),,,,,,,\n", "# nlvo: non-large-vessel occlusion MT: 480mins (8hr),,,,,,,\n", "# ivt: intra-veneous thrombolysis,,,,,,,\n", "# mt: mechanical thrombectomy,,,,,,,\n", "# t0: time zero, zero minutes after stroke onset.,,,,,,\n", "#,,,,,,,\n", "\n" ] } ], "source": [ "print(mrs_dists_notes)" ] }, { "cell_type": "markdown", "id": "8b78c6d5-298b-481e-9a6f-a017fa882d52", "metadata": {}, "source": [ "__Data set 2:__ Utility score for each mRS level.\n", "\n", "This does not have to be provided to the model. If it is not, default values are used. The default values are from the Wang et al. 2020 paper." ] }, { "cell_type": "code", "execution_count": 20, "id": "55e71a62-c948-4e25-8ea6-2f82372d956f", "metadata": {}, "outputs": [], "source": [ "utility_dists, utility_dists_notes = (\n", " outcome_utilities.import_utility_dists_from_file())" ] }, { "cell_type": "code", "execution_count": 21, "id": "c6e2548f-dd8f-4027-8aaf-1393dbfb0a75", "metadata": {}, "outputs": [ { "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", "
mRS=0mRS=1mRS=2mRS=3mRS=4mRS=5mRS=6
Name
Wang20200.970.880.740.550.20-0.190.0
Dijkland20180.950.930.830.620.420.110.0
\n", "
" ], "text/plain": [ " mRS=0 mRS=1 mRS=2 mRS=3 mRS=4 mRS=5 mRS=6\n", "Name \n", "Wang2020 0.97 0.88 0.74 0.55 0.20 -0.19 0.0\n", "Dijkland2018 0.95 0.93 0.83 0.62 0.42 0.11 0.0" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" } ], "source": [ "utility_dists" ] }, { "cell_type": "code", "execution_count": 22, "id": "b03de23e-3d9e-44db-8d71-5a33fe0b0db8", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "# \n", "# References:\n", "# Wang et al. 2020: Stroke. 2020;51:2411–2417\n", "# Dijkland et al. 2018: Stroke. 2018;49:965–971\n", "\n" ] } ], "source": [ "print(utility_dists_notes)" ] }, { "cell_type": "markdown", "id": "6747abf3-2775-46e8-ad01-7c84c61b1886", "metadata": {}, "source": [ "Choose one of these distributions to use as the utility weights:" ] }, { "cell_type": "code", "execution_count": 23, "id": "46b0d7ec-9f52-4aca-8c33-15100d9f10b3", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "array([ 0.97, 0.88, 0.74, 0.55, 0.2 , -0.19, 0. ])" ] }, "execution_count": 23, "metadata": {}, "output_type": "execute_result" } ], "source": [ "utility_weights = utility_dists.loc['Wang2020'].values\n", "\n", "utility_weights" ] }, { "attachments": {}, "cell_type": "markdown", "id": "5a29290e-351f-4488-8b66-3cd376e78169", "metadata": {}, "source": [ "### Custom data requirements\n", "\n", "If you would rather use custom data for the mRS and utility distributions, you can skip the above imports. The outcome model can accept any data in these formats:\n", "\n", "+ mRS distributions: must be a pandas DataFrame with:\n", " + columns for each mRS from 0 to 6 inclusive, named just as in the imported table above\n", " + rows for each group named just as in the imported table above\n", " + values between 0 and 1.\n", "\n", "+ utility weights: must be a numpy array with:\n", " + shape (7,), i.e. a one-dimensional array containing one value for each mRS from 0 to 6 inclusive\n", " + values consistent with a utility of 1 for full health and a utility of 0 for death.\n", " \n", "If the custom mRS distributions use different times of no effect, make sure that the new times are passed into the outcome model when it is initialised.\n", "\n", "### Running the model with custom data\n", "\n", "The following code creates another model object with the mRS distributions and utility weights given explicitly:" ] }, { "cell_type": "raw", "id": "46f3a20a-9fad-4966-84b0-2e5a84cbd372", "metadata": {}, "source": [ "continuous_outcome = Continuous_outcome(\n", " mrs_dists=mrs_dists,\n", " utility_weights=utility_weights,\n", " # ivt_time_no_effect_mins=378.0,\n", " # mt_time_no_effect_mins=480.0\n", ")" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.9.16" } }, "nbformat": 4, "nbformat_minor": 5 }