Skip to content

Commit eb70bef

Browse files
authored
Merge pull request #10 from pythonhealthdatascience/dev
Dev
2 parents 7444cc5 + dc1c64a commit eb70bef

32 files changed

+4299
-2186
lines changed

README.md

Lines changed: 83 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,39 +3,113 @@
33
# Stroke capacity planning model: python DES RAP
44

55
[![python](https://img.shields.io/badge/-Python_3.13.1-blue?logo=python&logoColor=white)](https://www.python.org/)
6-
![licence](https://img.shields.io/badge/Licence-MIT-green.svg?labelColor=gray)
6+
![licence](https://img.shields.io/badge/🛡️_Licence-MIT-green.svg?labelColor=gray)
77
[![Tests](https://github.com/pythonhealthdatascience/stroke_rap_python/actions/workflows/tests.yaml/badge.svg)](https://github.com/pythonhealthdatascience/stroke_rap_python/actions/workflows/tests.yaml)
88
[![Linting](https://github.com/pythonhealthdatascience/stroke_rap_python/actions/workflows/lint.yaml/badge.svg)](https://github.com/pythonhealthdatascience/stroke_rap_python/actions/workflows/lint.yaml)
9-
[![ORCID: Heather](https://img.shields.io/badge/ORCID_Amy_Heather-0000--0002--6596--3479-brightgreen)](https://orcid.org/0000-0002-6596-3479)
9+
[![ORCID](https://img.shields.io/badge/ORCID_Amy_Heather-0000--0002--6596--3479-A6CE39?&logo=orcid&logoColor=white)](https://orcid.org/0000-0002-6596-3479)
1010

1111
</div>
1212

1313
This repository applies the [Python DES RAP Template](https://github.com/pythonhealthdatascience/rap_template_python_des) to a real-life example:
1414

1515
> Monks T, Worthington D, Allen M, Pitt M, Stein K, James MA. A modelling tool for capacity planning in acute and community stroke services. BMC Health Serv Res. 2016 Sep 29;16(1):530. doi: [10.1186/s12913-016-1789-4](https://doi.org/10.1186/s12913-016-1789-4). PMID: 27688152; PMCID: PMC5043535.
1616
17+
Model diagram:
18+
1719
![](images/stroke_rehab_design.png)
1820

1921
<br>
2022

2123
## Installation
2224

23-
TBC
25+
Clone the repository locally:
26+
27+
```
28+
git clone https://github.com/pythonhealthdatascience/stroke_rap_python.git
29+
cd stroke_rap_python
30+
```
31+
32+
Use the provided `environment.yaml` file to set up a Python environment with `conda`:
2433

25-
<!-- TODO: Provide instructions for installing dependencies and setting up the environment. -->
34+
```
35+
conda env create --file environment.yaml
36+
conda activate
37+
```
38+
39+
The provided `environment.yaml` file is a snapshot of the environment used when creating the repository, including specific package versions. You can update this file if necessary, but be sure to test that everything continues to work as expected after any updates. Also note that some dependencies are not required for modelling, but instead served other purposes, like running `.ipynb` files and linting.
40+
41+
As an alternative, a `requirements.txt` file is provided which can be used to set up the environment with `virtualenv`. This is used by GitHub actions, which run much faster with a virtual environment than a conda environment. However, we recommend locally installing the environment using conda, as it will also manage the Python version for you. If using `virtualenv`, it won't fetch a specific version of Python - so please note the version listed in `environment.yaml`.
2642

2743
<br>
2844

2945
## How to run
3046

31-
TBC
47+
The simulation code is provided as a **package** within `simulation/`. There are notebooks executing the model and analysing the results in `notebooks/`.
48+
49+
To run the model with base parameters once or with replications:
50+
51+
```
52+
from simulation.parameters import Param
53+
from simulation.runner import Runner
54+
55+
param = Param()
56+
runner = Runner(param=param)
57+
58+
single_result = runner.run_single(run=0)
59+
rep_results = runner.run_reps()
60+
```
61+
62+
Example altering the model parameters:
63+
64+
```
65+
from simulation.parameters import Param, ASUArrivals, RehabRouting
66+
from simulation.runner import Runner
67+
68+
# Modified one of the arrival rates, some routing probabilities, and the
69+
# number of replications
70+
param = Param(
71+
asu_arrivals=ASUArrivals(tia=10),
72+
rehab_routing=RehabRouting(neuro_esd=0.2, neuro_other=0.8),
73+
number_of_runs=10
74+
)
75+
runner = Runner(param=param)
76+
rep_results = runner.run_reps()
77+
```
78+
79+
### Generating the results from the article
80+
81+
The original study used Simul8. Each of the outputs from that article have been replicated in this repository using Python:
82+
83+
* Figure 1. Simulation probability density function for occupancy of an acute stroke unit.
84+
* Figure 3. Simulated trade-off between the probability that a patient is delayed and the no. of acute beds available.
85+
* Table 2. Likelihood of delay. Current admissions versus 5% more admissions.
86+
* Table 3. Results of pooling of acute and rehab beds.
87+
* Supplementary Table 1. Likelihood of delay. Current admissions versus No Complex neurological patients.
88+
* Supplementary Table 3. Likelihood of delay. Current admissions versus ring fenced acute stroke beds.
89+
90+
To generate these, simply execute `notebooks/analysis.ipynb`.
91+
92+
#### Examples
93+
94+
**Figure 1**
95+
96+
Original:
97+
98+
![](docs/article/fig1.png)
99+
100+
From this repository:
101+
102+
![](outputs/occupancy_freq_asu.png)
103+
104+
**Figure 3**
105+
106+
Original:
32107

33-
<!-- Provide step-by-step instructions and examples.
108+
![](docs/article/fig3.png)
34109

35-
Clearly indicate which files will create each figure in the paper. Hypothetical example:
110+
From this repository:
36111

37-
* To generate **Figures 1 and 2**, execute `notebooks/base_case.ipynb`
38-
* To generate **Table 1** and **Figures 3 to 5**, execute `notebooks/scenario_analysis.ipynb` -->
112+
![](outputs/delay_prob_asu.png)
39113

40114
<br>
41115

File renamed without changes.

docs/article/fig1.png

24.4 KB
Loading

docs/article/fig2.png

58.5 KB
Loading

docs/article/fig3.png

22.9 KB
Loading

docs/log.md

Lines changed: 49 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -805,4 +805,52 @@ I then add new tests based on the python template and on the tests ran in https:
805805

806806
I add methods to check parameter validity in `Param`. This flagged that rehab other routing probability don't sum to 100% (88% and 13%) - but this is as described in the paper, and presumed to be due to rounding, so altered the validation test to allow.
807807

808-
> 💡 When explain tests, could do all in one section, like Tests > Back tests, Tests > Functional tests, Tests > Unit tests - and then on each of those pages, it's like, if you have parameter validation... if you have warm-up... etc. etc. suggesting tests could include.
808+
> 💡 When explain tests, could do all in one section, like Tests > Back tests, Tests > Functional tests, Tests > Unit tests - and then on each of those pages, it's like, if you have parameter validation... if you have warm-up... etc. etc. suggesting tests could include.
809+
810+
## Scenario logic
811+
812+
Having successfully implemented the base model generating Figure 1 and 3 (as in https://github.com/pythonhealthdatascience/llm_simpy/), I then moved on to the scenarios from Monks et al. 2016. These were:
813+
814+
0. **Current admissions** Current admission levels; beds are reserved for either acute or rehab patients
815+
1. **5% more admissions** A 5% increase in admissions across all patient subgroups.
816+
2. **Pooling of acute and rehab beds** The acute and rehab wards are co-located at same site. Beds are pooled and can be used by either acute or rehabilitation patients. Pooling of the total bed stock of 22 is compared to the pooling of an increased bed stock of 26.
817+
3. **Partial pooling of acute and rehab beds** The acute and rehab wards are co-located at same site. A subset of the 26 beds are pooled and can be used by either acute or rehab patients.
818+
4. **No complex-neurological cases** Complex neurological patients are excluded from the pathway in order to assess their impact on bed requirements
819+
820+
### Scenario 1 and 4
821+
822+
As from the supplementary:
823+
824+
> "Scenarios investigating increased demand multiply the mean arrival rates (supplied in main text) by the appropriate factor. To exclude a particular patient group, the mean inter-arrival time for that group is multiplied by a large number such that no arrivals will occur in the modelled time horizon."
825+
826+
Hence, it is understood that:
827+
828+
* **Scenario 1** can be achieved by multiplying all patient IAT by 1.05 (see below: 0.95).
829+
* **Scenario 4** can be achieved by multiplying IAT for complex neurological patients by a very high number (e.g. 10,000,000) - and can add a test which checks no patients are complex neurological.
830+
831+
## Using multiple replications
832+
833+
Altered `Runner` to output summary tables from across replications, and switched to using these for Figures 1 and 3.
834+
835+
## Scenario 1 + Table 2
836+
837+
Ran scenario 1 in `analysis.ipynb` and created Table 2. Noticed some differences.
838+
839+
I find scenario with same bed number, probability of delay drops. They find that it goes up.
840+
841+
Thinking through the logic, scenario has more arrivals -> wards more full -> expect delays for lower max bed numbers earlier -> expect higher probability of delay for lower bed numbers.
842+
843+
I then realised my mistake! I had actually lower admissions, as I'd multiplied IAT by 1.05, when I should've multiplied by 0.95.
844+
845+
## Scenario 4 + supplementary table 1
846+
847+
Ran scenario, adjusted function from table 2 so it could be used to make this table too.
848+
849+
## Scenario logic
850+
851+
We now have two remaining scenarios:
852+
853+
* Scenario 2: **Pooling of acute and rehab beds** The acute and rehab wards are co-located at same site. Beds are pooled and can be used by either acute or rehabilitation patients. Pooling of the total bed stock of 22 is compared to the pooling of an increased bed stock of 26.
854+
* Scenario 3: **Partial pooling of acute and rehab beds** The acute and rehab wards are co-located at same site. A subset of the 26 beds are pooled and can be used by either acute or rehab patients.
855+
856+
It took quite a while to understand the formula and how to implement them.

inputs/data_dictionary.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Data dictionary for `parameters.csv`
2+
3+
| Column | Data type | Description | Possible values |
4+
| - | - | - | - |
5+
| unit | str | Hospital unit | `asu`: Acute Stroke Unit<br>`rehab`: Rehabilitation Unit (post-acute recovery care) |
6+
| parameter | str | Type of operational metric | `iat`: Inter-arrival time (time between patient admissions)<br>`los`: Length of stay (duration from admission to discharge)<br>`routing`: Transition probability between care pathways |
7+
| type | str | Patient classification or care transition path | **For `iat`/`los`:**<br>`stroke`: Stroke patients<br>`stroke_esd`: Stroke patients transferred to Early Supported Discharge<br>`stroke_no_esd`: Stroke patients not transferred to Early Supported Discharge<br>`tia`: Transient Ischemic Attack patients<br>`neuro`: Complex neurological patients<br>`other`: Other patient types<br><br>**For `routing`:**<br>`[diagnosis]_rehab`: Probability of transferring to rehabilitation unit<br>`[diagnosis]_esd`: Probability of Early Supported Discharge<br>`[diagnosis]_other`: Probability of other discharge pathways |
8+
| mean | float | **For `iat`:** Mean days between admissions<br>**For `los`:** Mean days in unit<br>**For `routing`:** Probability (0-1 scale) | - |
9+
| sd | float | Standard deviation of the mean | - |

inputs/parameters.csv

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
unit,parameter,type,mean,sd
2+
asu,iat,stroke,1.2,NA
3+
asu,iat,tia,9.3,NA
4+
asu,iat,neuro,3.6,NA
5+
asu,iat,other,3.2,NA
6+
rehab,iat,stroke,21.8,NA
7+
rehab,iat,neuro,31.7,NA
8+
rehab,iat,other,28.6,NA
9+
asu,los,stroke_no_esd,7.4,8.61
10+
asu,los,stroke_esd,4.6,4.8
11+
asu,los,tia,1.8,2.3
12+
asu,los,neuro,4,5
13+
asu,los,other,3.8,5.2
14+
rehab,los,stroke_no_esd,28.4,27.2
15+
rehab,los,stroke_esd,30.3,2un3.1
16+
rehab,los,tia,18.7,23.5
17+
rehab,los,neuro,27.6,28.4
18+
rehab,los,other,16.1,14.1
19+
asu,routing,stroke_rehab,0.24,NA
20+
asu,routing,stroke_esd,0.13,NA
21+
asu,routing,stroke_other,0.63,NA
22+
asu,routing,tia_rehab,0.01,NA
23+
asu,routing,tia_esd,0.01,NA
24+
asu,routing,tia_other,0.98,NA
25+
asu,routing,neuro_rehab,0.11,NA
26+
asu,routing,neuro_esd,0.05,NA
27+
asu,routing,neuro_other,0.84,NA
28+
asu,routing,other_rehab,0.05,NA
29+
asu,routing,other_esd,0.1,NA
30+
asu,routing,other_other,0.85,NA
31+
rehab,routing,stroke_esd,0.4,NA
32+
rehab,routing,stroke_other,0.6,NA
33+
rehab,routing,tia_esd,0,NA
34+
rehab,routing,tia_other,1,NA
35+
rehab,routing,neuro_esd,0.09,NA
36+
rehab,routing,neuro_other,0.91,NA
37+
rehab,routing,other_esd,0.13,NA
38+
rehab,routing,other_other,0.88,NA

0 commit comments

Comments
 (0)