Stroke pathway simulation - generation of results from alternative scenarios#

This notebook runs alternative pathway simulations, with adjusted pathway parameters. The scenarios are:

  1. Base: Uses the hospitals’ recorded pathway statistics in SSNAP (same as validation notebook)

  2. Speed: Sets 95% of patients having a scan within 4 hours of arrival, and all patients have 15 minutes arrival to scan and 15 minutes scan to needle.

  3. Onset-known: Sets the proportion of patients with a known onset time of stroke to the national upper quartile if currently less than the national upper quartile (leave any greater than the upper national quartile at their current level).

  4. Benchmark: The benchmark thrombolysis rate takes the likelihood to give thrombolysis for patients scanned within 4 hours of onset from the majority vote of the 30 hospitals with the highest predicted thrombolysis use in a standard 10k cohort set of patients. These are from Random Forests models.

  5. Combine Speed and Onset-known

  6. Combine Speed and Benchmark

  7. Combine Onset-known and Benchmark

  8. Combine Speed, Onset-known and Benchmark

Results are saved for each hospital and scenario. Detailed analysis will be performed in subsequent notebooks

Import libraries and data#

# Import libraries
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
from pathway import model_ssnap_pathway_scenarios

# load data from csv and store in pandas dataframe
filename = './hosp_performance_output/hospital_performance.csv'
hospital_performance_original = pd.read_csv(filename, index_col=0)

Get results of alternative scenarios#

Base scenario#

The base scenario uses the hospitals’ recorded pathway statistics in SSNAP (same as validation notebook)

results_all = model_ssnap_pathway_scenarios(hospital_performance_original)
results_all['scenario'] = 'base'

# Save pathway stats used
hospital_performance_original.to_csv('output/performance_base.csv')

Speed (30 minute arrival to needle)#

The adjusted speed scenario sets 95% of patients having a scan within 4 hours of arrival, and all patients have 15 minutes arrival to scan and 15 minutes scan to needle.

# Create scenarios
hospital_performance = hospital_performance_original.copy()
hospital_performance['scan_within_4_hrs'] = 0.95
hospital_performance['arrival_scan_arrival_mins_mu'] = np.log(15)
hospital_performance['arrival_scan_arrival_mins_sigma'] = 0
hospital_performance['scan_needle_mins_mu'] = np.log(15)
hospital_performance['scan_needle_mins_sigma'] = 0
# Get results
results = model_ssnap_pathway_scenarios(hospital_performance)
results['scenario'] = 'speed'

# Add to results_all
results_all = pd.concat([results_all, results], axis=0)

# Save pathway stats used
hospital_performance.to_csv('output/performance_speed.csv')

Known onset#

Set the proportion of patients with a known onset time of stroke to the national upper quartile if currently less than the national upper quartile (leave any greater than the upper national quartile at their current level).

# Create scenarios
hospital_performance = hospital_performance_original.copy()

onset_known = hospital_performance_original['onset_known']
onset_known_upper_q = np.percentile(onset_known, 75)
adjusted_onset_known = []
for val in onset_known:
    if val > onset_known_upper_q:
        adjusted_onset_known.append(val)
    else:
        adjusted_onset_known.append(onset_known_upper_q)
hospital_performance['onset_known'] = adjusted_onset_known
# Get results
results = model_ssnap_pathway_scenarios(hospital_performance)
results['scenario'] = 'onset'

# Add to results_all
results_all = pd.concat([results_all, results], axis=0)

# Save pathway stats used
hospital_performance.to_csv('output/performance_onset.csv')

Use benchmark thrombolysis#

The benchmark thrombolysis rate takes the likelihood to give thrombolysis for patients scanned within 4 hours of onset from the majority vote of the 30 hospitals with the highest predicted thrombolysis use in a standard 10k cohort set of patients. These are from Random Forests models.

See Random Forests notebooks: Benchmark hospitals and How would thrombolysis use change if clinical decisions were made by hospitals with the highest current thrombolysis rate?

# Load benchmark rates
filename = './hosp_performance_output/benchmark_4hr_scan.csv'
benchmark = pd.read_csv(filename, index_col=0)
# Convert from percentage to fraction
benchmark *= 0.01
# Merge in benchmark rates (to ensure order is correct)
hospital_performance = hospital_performance_original.copy()
hospital_performance = hospital_performance.merge(
    benchmark, left_index=True, right_index=True, how='left')
hospital_performance['eligable'] = hospital_performance['benchmark']
# Get results
results = model_ssnap_pathway_scenarios(hospital_performance)
results['scenario'] = 'benchmark'

# Add to results_all
results_all = pd.concat([results_all, results], axis=0)

# Save pathway stats used
hospital_performance.to_csv('output/performance_benchmark.csv')

Combine speed and onset known#

  • 95% patients have scan within 4 hours of arrival

  • 30 min arrival to needle (15 minute arrival-to-scan, 15 minute scan-to-needle)

  • Proportion of patients with known stroke onset time set to upper quartile if currently lower

# Create scenarios
hospital_performance = hospital_performance_original.copy()

# Speed
hospital_performance['scan_within_4_hrs'] = 0.95
hospital_performance['arrival_scan_arrival_mins_mu'] = np.log(15)
hospital_performance['arrival_scan_arrival_mins_sigma'] = 0
hospital_performance['scan_needle_mins_mu'] = np.log(15)
hospital_performance['scan_needle_mins_sigma'] = 0

# Onset known
onset_known = hospital_performance_original['onset_known']
onset_known_upper_q = np.percentile(onset_known, 75)
adjusted_onset_known = []
for val in onset_known:
    if val > onset_known_upper_q:
        adjusted_onset_known.append(val)
    else:
        adjusted_onset_known.append(onset_known_upper_q)
hospital_performance['onset_known'] = adjusted_onset_known

# Save pathway stats used
hospital_performance.to_csv('output/performance_speed_onset.csv')
# Get results
results = model_ssnap_pathway_scenarios(hospital_performance)
results['scenario'] = 'speed_onset'

# Add to results_all
results_all = pd.concat([results_all, results], axis=0)

Combine speed and benchmark#

  • 95% patients have scan within 4 hours of arrival

  • 30 min arrival to needle (15 minute arrival-to-scan, 15 minute scan-to-needle)

  • Decision to thrombolyse patients if scanned within 4 hours of known onset as predicted from majority vote of 30 benchmark hospitals

# Create scenarios
hospital_performance = hospital_performance_original.copy()

# Speed
hospital_performance['scan_within_4_hrs'] = 0.95
hospital_performance['arrival_scan_arrival_mins_mu'] = np.log(15)
hospital_performance['arrival_scan_arrival_mins_sigma'] = 0
hospital_performance['scan_needle_mins_mu'] = np.log(15)
hospital_performance['scan_needle_mins_sigma'] = 0

# Benchmark
hospital_performance = hospital_performance.merge(
    benchmark, left_index=True, right_index=True, how='left')
hospital_performance['eligable'] = hospital_performance['benchmark']
# Get results
results = model_ssnap_pathway_scenarios(hospital_performance)
results['scenario'] = 'speed_benchmark'

# Add to results_all
results_all = pd.concat([results_all, results], axis=0)

# Save pathway stats used
hospital_performance.to_csv('output/performance_speed_benchmark.csv')

Combine onset-known and benchmark#

  • Proportion of patients with known stroke onset time set to upper quartile if currently lower

  • Decision to thrombolyse patients if scanned within 4 hours of known onset as predicted from majority vote of 30 benchmark hospitals

# Create scenarios
hospital_performance = hospital_performance_original.copy()

# Onset known
onset_known = hospital_performance_original['onset_known']
onset_known_upper_q = np.percentile(onset_known, 75)
adjusted_onset_known = []
for val in onset_known:
    if val > onset_known_upper_q:
        adjusted_onset_known.append(val)
    else:
        adjusted_onset_known.append(onset_known_upper_q)
hospital_performance['onset_known'] = adjusted_onset_known

# Benchmark
hospital_performance = hospital_performance.merge(
    benchmark, left_index=True, right_index=True, how='left')
hospital_performance['eligable'] = hospital_performance['benchmark']
# Get results
results = model_ssnap_pathway_scenarios(hospital_performance)
results['scenario'] = 'onset_benchmark'

# Add to results_all
results_all = pd.concat([results_all, results], axis=0)

# Save pathway stats used
hospital_performance.to_csv('output/performance_onset_benchmark.csv')

Combine speed, onset-known, and benchmark#

  • 95% patients have scan within 4 hours of arrival

  • 30 min arrival to needle (15 minute arrival-to-scan, 15 minute scan-to-needle)

  • Proportion of patients with known stroke onset time set to upper quartile if currently lower

  • Decision to thrombolyse patients if scanned within 4 hours of known onset as predicted from majority vote of 30 benchmark hospitals

# Create scenarios
hospital_performance = hospital_performance_original.copy()

# Speed
hospital_performance['scan_within_4_hrs'] = 0.95
hospital_performance['arrival_scan_arrival_mins_mu'] = np.log(15)
hospital_performance['arrival_scan_arrival_mins_sigma'] = 0
hospital_performance['scan_needle_mins_mu'] = np.log(15)
hospital_performance['scan_needle_mins_sigma'] = 0

# Onset known
onset_known = hospital_performance_original['onset_known']
onset_known_upper_q = np.percentile(onset_known, 75)
adjusted_onset_known = []
for val in onset_known:
    if val > onset_known_upper_q:
        adjusted_onset_known.append(val)
    else:
        adjusted_onset_known.append(onset_known_upper_q)
hospital_performance['onset_known'] = adjusted_onset_known

# Benchmark
hospital_performance = hospital_performance.merge(
    benchmark, left_index=True, right_index=True, how='left')
hospital_performance['eligable'] = hospital_performance['benchmark']
# Get results
results = model_ssnap_pathway_scenarios(hospital_performance)
results['scenario'] = 'speed_onset_benchmark'

# Add to results_all
results_all = pd.concat([results_all, results], axis=0)

# Save pathway stats used
hospital_performance.to_csv('output/performance_speed_onset_benchmark.csv')

Same patient characteristics to all hospitals#

# Get predicted cohort thrombolysis for patients arrived in 4 hours
cohort_rate = pd.read_csv(
    '../random_forest/predictions/corhort_rates.csv', index_col='hospital')
cohort_rate['cohort_rate'] /= 100 # Convert from percent to fraction

# Create scenarios
hospital_performance = hospital_performance_original.copy()

hospital_performance = hospital_performance.merge(
    cohort_rate['cohort_rate'], left_index=True, right_index=True)

# Set all hopsital to 1000 arrivals
hospital_performance['arrivals'] = 1000

# Set aged 80+ to national average for arrivaks within 4 hours of stroke onset
hospital_performance['80_plus'] = 0.423

# Set known arrival within 4 hours to 58% of onset_known
hospital_performance['known_arrival_within_4hrs'] = 0.58

# Set onet to arrival to national average
hospital_performance['onset_arrival_mins_mu'] = 4.58
hospital_performance['onset_arrival_mins_sigma'] = 0.56

# Set eligible to prop of 10k cohort predicted to receive thrombolysis
# Adjust for rate being just for those scanned in 4 hours from onset 
correction = 1 / 0.827 # 82.7% in 10k cohort scanned in 4 hours from onset
hospital_performance['eligable'] = hospital_performance['cohort_rate'] * correction

# Get results
results = model_ssnap_pathway_scenarios(hospital_performance)
results['scenario'] = 'same_patient_characteristics'

# Add to results_all
results_all = pd.concat([results_all, results], axis=0)

# Save pathway stats used
hospital_performance.to_csv('output/same_patient_characteristics.csv')
results
Baseline_good_outcomes_(median) Baseline_good_outcomes_per_1000_patients_(low_5%) Baseline_good_outcomes_per_1000_patients_(high_95%) Baseline_good_outcomes_per_1000_patients_(mean) Baseline_good_outcomes_per_1000_patients_(stdev) Baseline_good_outcomes_per_1000_patients_(95ci) Percent_Thrombolysis_(median%) Percent_Thrombolysis_(low_5%) Percent_Thrombolysis_(high_95%) Percent_Thrombolysis_(mean) ... Percent_Thrombolysis_(95ci) Additional_good_outcomes_per_1000_patients_(median) Additional_good_outcomes_per_1000_patients_(low_5%) Additional_good_outcomes_per_1000_patients_(high_95%) Additional_good_outcomes_per_1000_patients_(mean) Additional_good_outcomes_per_1000_patients_(stdev) Additional_good_outcomes_per_1000_patients_(95ci) Onset_to_needle_(mean) calibration scenario
AGNOF1041H 256.33 231.00 280.33 256.68 15.27 2.99 11.03 8.94 12.82 11.06 ... 0.22 9.21 7.32 11.08 9.21 1.12 0.22 164.15 1.0 same_patient_characteristics
AKCGO9726K 256.34 236.79 280.84 256.40 13.15 2.58 22.48 20.03 24.50 22.39 ... 0.27 19.97 17.46 21.74 19.82 1.33 0.26 151.32 1.0 same_patient_characteristics
AOBTM3098N 257.00 226.00 290.10 257.08 19.05 3.73 8.60 6.80 10.61 8.71 ... 0.24 6.47 4.86 8.17 6.62 0.97 0.19 182.50 1.0 same_patient_characteristics
APXEE8191H 256.26 227.33 291.91 256.63 22.71 4.45 13.10 10.71 15.95 13.21 ... 0.31 10.16 8.20 12.67 10.30 1.31 0.26 177.40 1.0 same_patient_characteristics
ATDID5461S 254.55 218.00 316.36 259.09 30.24 5.93 7.27 5.45 10.18 7.59 ... 0.30 5.23 3.33 7.26 5.29 1.19 0.23 197.94 1.0 same_patient_characteristics
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
YPKYH1768F 256.00 220.00 292.40 258.40 23.60 4.63 7.20 4.80 10.42 7.47 ... 0.34 4.98 3.26 7.24 4.98 1.25 0.24 206.28 1.0 same_patient_characteristics
YQMZV4284N 256.98 220.39 293.44 256.98 22.35 4.38 16.20 12.53 18.72 15.92 ... 0.39 12.97 9.91 15.56 12.87 1.75 0.34 170.94 1.0 same_patient_characteristics
ZBVSO0975W 258.35 229.40 289.76 258.08 17.57 3.44 7.80 5.35 10.02 7.66 ... 0.29 6.27 4.09 8.38 6.23 1.31 0.26 168.60 1.0 same_patient_characteristics
ZHCLE1578P 256.28 228.64 281.60 256.71 16.16 3.17 10.87 9.05 12.33 10.76 ... 0.20 8.83 7.34 10.38 8.78 0.89 0.17 169.10 1.0 same_patient_characteristics
ZRRCV7012C 256.28 229.48 286.43 257.04 16.69 3.27 11.22 9.36 13.07 11.19 ... 0.23 8.62 7.10 10.23 8.67 1.00 0.20 178.32 1.0 same_patient_characteristics

132 rows × 21 columns

results_all
Baseline_good_outcomes_(median) Baseline_good_outcomes_per_1000_patients_(low_5%) Baseline_good_outcomes_per_1000_patients_(high_95%) Baseline_good_outcomes_per_1000_patients_(mean) Baseline_good_outcomes_per_1000_patients_(stdev) Baseline_good_outcomes_per_1000_patients_(95ci) Percent_Thrombolysis_(median%) Percent_Thrombolysis_(low_5%) Percent_Thrombolysis_(high_95%) Percent_Thrombolysis_(mean) ... Percent_Thrombolysis_(95ci) Additional_good_outcomes_per_1000_patients_(median) Additional_good_outcomes_per_1000_patients_(low_5%) Additional_good_outcomes_per_1000_patients_(high_95%) Additional_good_outcomes_per_1000_patients_(mean) Additional_good_outcomes_per_1000_patients_(stdev) Additional_good_outcomes_per_1000_patients_(95ci) Onset_to_needle_(mean) calibration scenario
AGNOF1041H 257.82 228.02 287.70 258.00 17.26 3.38 15.28 12.95 17.15 15.20 ... 0.28 12.78 10.72 14.81 12.76 1.27 0.25 163.02 1.0 base
AKCGO9726K 259.84 241.38 286.26 260.74 14.08 2.76 14.79 13.29 16.89 14.91 ... 0.20 13.09 11.68 15.13 13.21 1.02 0.20 154.07 1.0 base
AOBTM3098N 243.00 211.90 272.00 242.04 19.53 3.83 7.80 6.19 9.40 7.80 ... 0.22 5.61 4.27 7.34 5.67 0.98 0.19 183.15 1.0 base
APXEE8191H 235.76 205.01 275.74 239.00 21.02 4.12 10.02 8.42 12.53 10.40 ... 0.26 7.46 5.89 9.53 7.59 1.20 0.24 180.86 1.0 base
ATDID5461S 232.73 196.36 272.73 236.47 24.64 4.83 9.09 6.89 12.00 9.17 ... 0.33 6.12 4.62 8.61 6.28 1.20 0.24 188.62 1.0 base
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
YPKYH1768F 256.00 220.00 292.40 258.40 23.60 4.63 7.20 4.80 10.42 7.47 ... 0.34 4.98 3.26 7.24 4.98 1.25 0.24 206.28 1.0 same_patient_characteristics
YQMZV4284N 256.98 220.39 293.44 256.98 22.35 4.38 16.20 12.53 18.72 15.92 ... 0.39 12.97 9.91 15.56 12.87 1.75 0.34 170.94 1.0 same_patient_characteristics
ZBVSO0975W 258.35 229.40 289.76 258.08 17.57 3.44 7.80 5.35 10.02 7.66 ... 0.29 6.27 4.09 8.38 6.23 1.31 0.26 168.60 1.0 same_patient_characteristics
ZHCLE1578P 256.28 228.64 281.60 256.71 16.16 3.17 10.87 9.05 12.33 10.76 ... 0.20 8.83 7.34 10.38 8.78 0.89 0.17 169.10 1.0 same_patient_characteristics
ZRRCV7012C 256.28 229.48 286.43 257.04 16.69 3.27 11.22 9.36 13.07 11.19 ... 0.23 8.62 7.10 10.23 8.67 1.00 0.20 178.32 1.0 same_patient_characteristics

1188 rows × 21 columns

hospital_performance
thrombolysis_rate admissions 80_plus onset_known known_arrival_within_4hrs onset_arrival_mins_mu onset_arrival_mins_sigma scan_within_4_hrs arrival_scan_arrival_mins_mu arrival_scan_arrival_mins_sigma onset_scan_4_hrs eligable scan_needle_mins_mu scan_needle_mins_sigma cohort_rate arrivals
AGNOF1041H 0.154839 671.666667 0.423 0.635236 0.58 4.58 0.56 0.965596 1.665700 1.497966 0.935867 0.335671 3.669602 0.664462 0.2776 1000
AKCGO9726K 0.158892 1143.333333 0.423 0.970845 0.58 4.58 0.56 0.955882 2.834183 0.999719 0.908425 0.452842 2.904479 0.874818 0.3745 1000
AOBTM3098N 0.085885 500.666667 0.423 0.619174 0.58 4.58 0.56 0.935043 3.471419 1.254744 0.846435 0.314389 3.694918 0.518929 0.2600 1000
APXEE8191H 0.098634 439.333333 0.423 0.716237 0.58 4.58 0.56 0.966899 3.312930 0.714465 0.904505 0.362394 3.585094 0.751204 0.2997 1000
ATDID5461S 0.090689 275.666667 0.423 0.573156 0.58 4.58 0.56 0.878594 4.125690 0.549301 0.865455 0.313422 3.497262 0.608126 0.2592 1000
... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ... ...
YPKYH1768F 0.105193 250.333333 0.423 0.585885 0.58 4.58 0.56 0.952681 3.779215 0.872809 0.844371 0.269045 3.982100 0.683223 0.2225 1000
YQMZV4284N 0.104186 358.333333 0.423 0.945116 0.58 4.58 0.56 0.948936 3.574735 0.912298 0.798206 0.361306 3.285165 0.463749 0.2988 1000
ZBVSO0975W 0.081602 449.333333 0.423 0.465134 0.58 4.58 0.56 0.972222 2.860226 0.990966 0.930952 0.317170 3.606046 0.575788 0.2623 1000
ZHCLE1578P 0.112647 796.000000 0.423 0.733668 0.58 4.58 0.56 0.949830 3.306916 0.842940 0.892569 0.291898 3.276043 0.795401 0.2414 1000
ZRRCV7012C 0.063058 597.333333 0.423 0.779576 0.58 4.58 0.56 0.977305 3.743456 0.662710 0.851959 0.288755 3.261270 0.803624 0.2388 1000

132 rows × 16 columns

Save results#

results_all['stroke_team'] = results_all.index
results_all.to_csv('./output/scenario_results.csv', index=False)