Reproducing in-text result 2

This notebook aims to reproduce in-text result 2 from Shoaib M, Ramamohan V. Simulation modeling and analysis of primary health center operations. SIMULATION 98(3):183-208. (2022). https://doi.org/10.1177/00375497211030931.

In-text result 2:

“To address this, we experimented with letting the staff nurse (whose utilisation is approximately 32%) take over the administrative work. This led to a 12% drop in the utilisation level, which implied that the doctor’s utilisation still exceeded 100%. Implementing this measure resulted in increasing the staff nurse utilisation to nearly 40%.”

Parameters

This result starts with the doctor utilisation from Figure 2A which is over 100% when patient load is 170 (IAT 3) and appointment times are 5 minutes (mean 5, SD 1, boundary 2).

The variant introduced is to give all administrative work to the staff nurse.

Set up

# To run model
import PHC
from reproduction_helpers import process_results

# To import results and produce figures
import xlrd
import pandas as pd
import os
import matplotlib.pyplot as plt
import numpy as np

# To speed up run time
from multiprocessing import Pool

# Additional package to record runtime of this notebook
import time
start = time.time()
# Paths to save image files to
output_folder = '../outputs'
save_path = os.path.join(output_folder, 'intext2.csv')

Run model

# Parameters used in both models
base_model = {
    'OPD_iat': 3,
    'rep_file': 'arr170',
    'mean': 5,
    'sd': 1,
    'consult_boundary_1': 2,
    'consult_boundary_2': 2
}

# Model variants
variants = [
    {
        'admin_doc_to_staff': False,
        'rep_file': 'in2_admin_doctor.xls'
    },
    {
        'admin_doc_to_staff': True,
        'rep_file': 'in2_admin_nurse.xls'
    },
]
# Combine dictionaries
dict_list = []
for var in variants:
    dict_list.append({**base_model, **var})

# Append 's_' to all items
for i, d in enumerate(dict_list):
    dict_list[i] = {f's_{k}': v for k, v in d.items()}

# View dictionaries
dict_list
[{'s_OPD_iat': 3,
  's_rep_file': 'in2_admin_doctor.xls',
  's_mean': 5,
  's_sd': 1,
  's_consult_boundary_1': 2,
  's_consult_boundary_2': 2,
  's_admin_doc_to_staff': False},
 {'s_OPD_iat': 3,
  's_rep_file': 'in2_admin_nurse.xls',
  's_mean': 5,
  's_sd': 1,
  's_consult_boundary_1': 2,
  's_consult_boundary_2': 2,
  's_admin_doc_to_staff': True}]
# Wrapper function to allow input of dictionary with pool
def wrapper(d):
    return PHC.main(**d)

# Create a process pool that uses all CPUs
with Pool() as pool:
    # Run PHC.main() using each of inputs from config
    pool.map(wrapper, dict_list)
 No of replications done No of replications done  00

 No of replications done 1
 No of replications done 1
 No of replications done 2
 No of replications done 2
 No of replications done 3
 No of replications done 3
 No of replications done 4
 No of replications done 4
 No of replications done 5
 No of replications done 5
 No of replications done 6
 No of replications done 6
 No of replications done 7
 No of replications done 7
 No of replications done 8
 No of replications done 8
 No of replications done 9
 No of replications done 9

Process results

# Process results
data = process_results([i['s_rep_file'] for i in dict_list], xls=True)
def get_utilisation(index_name, new_name):
    '''
    Creates dataframe with columns for utilisation (for a given row) before and
    after admin change and the change in utilisation..

    Parameters:
    -----------
    index_name : string
        Name of row with utilisation dat
    new_name : string
        To rename the utilisation row (e.g. doc occ -> doctor utilisation)

    Returns:
    --------
    util : pandas DataFrame
        Dataframe with three columns for utilisation before and after admin,
        and change in utilisation.
    '''
    # Get utilisation
    util = round(pd.DataFrame(data.loc[index_name]).T, 3)

    # Find change
    util['Change'] = util['in2_admin_nurse'] - util['in2_admin_doctor']

    # Rename index
    util = util.rename_axis('Output')
    # Rename row
    util = util.rename({index_name: new_name})
    # Rename columns for clarity for readers
    util = util.rename({
        'in2_admin_doctor': 'Original utilisation',
        'in2_admin_nurse': (
            'Utilisation if admin is assigned to the staff nurse')
    }, axis=1)

    return util
# Get results for doctor utilisation and staff nurse utilisation
util = pd.concat([
    get_utilisation('doc occ', 'Doctor utilisation'),
    get_utilisation('staff nurse occ', 'Staff nurse utilisation')])

# Display results
display(util)

# Save results
util.to_csv(save_path, index=True)
Original utilisation Utilisation if admin is assigned to the staff nurse Change
Output
Doctor utilisation 1.141 1.023 -0.118
Staff nurse utilisation 0.326 0.404 0.078

Run time

# Find run time in seconds
end = time.time()
runtime = round(end-start)

# Display converted to minutes and seconds
print(f'Notebook run time: {runtime//60}m {runtime%60}s')
Notebook run time: 2m 29s