Combine populations for weighted mRS distributions#

Use the patient population to combine the mRS distributions from the separate cohorts.

Plain English summary#

In the previous notebook we calculated outcomes for patients across all of England and Wales. This assumed fixed times to treatment except for travel times to the stroke units. We calculated one set of times for the drip-and-ship scenario, where patients first go to their nearest stroke unit and are later transferred to the MT unit if they need thrombectomy, and a second set of times for the mothership scenario, where every patient goes directly to the MT unit.

The existing data has separate entries for each cohort of patients:

  • patients with an nLVO treated with IVT

  • patients with a LVO treated with IVT only

  • patients with a LVO treated with MT only

  • patients with a LVO treated with both IVT and MT

In this notebook we will combine the data of multiple groups of patients.

We will then combine all patients around England and Wales to create one set of mRS distributions that applies nationally.

Aims#

To find the averaged mRS distributions after treatment for the following groups:

  • patients with a LVO and a mix of the available treatment types

  • patients with an nLVO and patients with a LVO and a mix of the available treatment types

Then to combine the mRS distributions for any LSOA where redirection affects which stroke unit is attended first.

Method#

Use the example patient proportions to calculate a weighted sum of the separate cohorts.

The national mRS distribution uses a weighted combination of the mRS distributions of all LSOAs where redirection affects which stroke unit is attended first. The weights are the predicted number of admissions from each LSOA as calculated in a previous notebook.

Notebook setup#

import pandas as pd
import numpy as np
import os

import stroke_outcome.outcome_utilities
dir_output = 'output'

Import data#

Patient proportions:

proportions = pd.read_csv(
    os.path.join(dir_output, 'patient_proportions.csv'),
    index_col=0, header=None).squeeze()
proportions
0
haemorrhagic         0.13600
lvo_no_treatment     0.14648
lvo_ivt_only         0.00840
lvo_ivt_mt           0.08500
lvo_mt_only          0.01500
nlvo_no_treatment    0.50252
nlvo_ivt             0.10660
Name: 1, dtype: float64

Calculate some additional proportions:

# Proportion of treated LVO patients:
prop_lvo_treated = 0.0

for key, value in proportions.items():
    if (('lvo' in key) & ('nlvo' not in key) & ('no_treat' not in key)):
        print(key)
        prop_lvo_treated += value

prop_lvo_treated
lvo_ivt_only
lvo_ivt_mt
lvo_mt_only
0.10840000000000001
# Proportion of treated ischaemic patients:
prop_ischaemic_treated = 0.0

for key, value in proportions.items():
    if (('lvo' in key) & ('no_treat' not in key)):
        print(key)
        prop_ischaemic_treated += value

prop_ischaemic_treated
lvo_ivt_only
lvo_ivt_mt
lvo_mt_only
nlvo_ivt
0.21500000000000002
# Proportion of ischaemic patients:
prop_ischaemic = 1.0 - proportions['haemorrhagic']

prop_ischaemic
0.864

mRS distributions:

df_mrs = pd.read_csv(os.path.join(dir_output, 'cohort_mrs_dists.csv'), index_col=0)
df_mrs.info()
<class 'pandas.core.frame.DataFrame'>
Index: 34752 entries, Adur 001A to York 024F
Data columns (total 67 columns):
 #   Column                             Non-Null Count  Dtype  
---  ------                             --------------  -----  
 0   closest_ivt_time                   34752 non-null  float64
 1   closest_ivt_unit                   34752 non-null  object 
 2   closest_mt_time                    34752 non-null  float64
 3   closest_mt_unit                    34752 non-null  object 
 4   transfer_mt_time                   34752 non-null  float64
 5   transfer_mt_unit                   34752 non-null  object 
 6   mt_transfer_required               34752 non-null  bool   
 7   ivt_drip_ship                      34752 non-null  float64
 8   mt_drip_ship                       34752 non-null  float64
 9   ivt_mothership                     34752 non-null  float64
 10  mt_mothership                      34752 non-null  float64
 11  drip_ship_nlvo_ivt_mrs_dists_0     34752 non-null  float64
 12  drip_ship_nlvo_ivt_mrs_dists_1     34752 non-null  float64
 13  drip_ship_nlvo_ivt_mrs_dists_2     34752 non-null  float64
 14  drip_ship_nlvo_ivt_mrs_dists_3     34752 non-null  float64
 15  drip_ship_nlvo_ivt_mrs_dists_4     34752 non-null  float64
 16  drip_ship_nlvo_ivt_mrs_dists_5     34752 non-null  float64
 17  drip_ship_nlvo_ivt_mrs_dists_6     34752 non-null  float64
 18  drip_ship_lvo_ivt_mrs_dists_0      34752 non-null  float64
 19  drip_ship_lvo_ivt_mrs_dists_1      34752 non-null  float64
 20  drip_ship_lvo_ivt_mrs_dists_2      34752 non-null  float64
 21  drip_ship_lvo_ivt_mrs_dists_3      34752 non-null  float64
 22  drip_ship_lvo_ivt_mrs_dists_4      34752 non-null  float64
 23  drip_ship_lvo_ivt_mrs_dists_5      34752 non-null  float64
 24  drip_ship_lvo_ivt_mrs_dists_6      34752 non-null  float64
 25  drip_ship_lvo_ivt_mt_mrs_dists_0   34752 non-null  float64
 26  drip_ship_lvo_ivt_mt_mrs_dists_1   34752 non-null  float64
 27  drip_ship_lvo_ivt_mt_mrs_dists_2   34752 non-null  float64
 28  drip_ship_lvo_ivt_mt_mrs_dists_3   34752 non-null  float64
 29  drip_ship_lvo_ivt_mt_mrs_dists_4   34752 non-null  float64
 30  drip_ship_lvo_ivt_mt_mrs_dists_5   34752 non-null  float64
 31  drip_ship_lvo_ivt_mt_mrs_dists_6   34752 non-null  float64
 32  drip_ship_lvo_mt_mrs_dists_0       34752 non-null  float64
 33  drip_ship_lvo_mt_mrs_dists_1       34752 non-null  float64
 34  drip_ship_lvo_mt_mrs_dists_2       34752 non-null  float64
 35  drip_ship_lvo_mt_mrs_dists_3       34752 non-null  float64
 36  drip_ship_lvo_mt_mrs_dists_4       34752 non-null  float64
 37  drip_ship_lvo_mt_mrs_dists_5       34752 non-null  float64
 38  drip_ship_lvo_mt_mrs_dists_6       34752 non-null  float64
 39  mothership_nlvo_ivt_mrs_dists_0    34752 non-null  float64
 40  mothership_nlvo_ivt_mrs_dists_1    34752 non-null  float64
 41  mothership_nlvo_ivt_mrs_dists_2    34752 non-null  float64
 42  mothership_nlvo_ivt_mrs_dists_3    34752 non-null  float64
 43  mothership_nlvo_ivt_mrs_dists_4    34752 non-null  float64
 44  mothership_nlvo_ivt_mrs_dists_5    34752 non-null  float64
 45  mothership_nlvo_ivt_mrs_dists_6    34752 non-null  float64
 46  mothership_lvo_ivt_mrs_dists_0     34752 non-null  float64
 47  mothership_lvo_ivt_mrs_dists_1     34752 non-null  float64
 48  mothership_lvo_ivt_mrs_dists_2     34752 non-null  float64
 49  mothership_lvo_ivt_mrs_dists_3     34752 non-null  float64
 50  mothership_lvo_ivt_mrs_dists_4     34752 non-null  float64
 51  mothership_lvo_ivt_mrs_dists_5     34752 non-null  float64
 52  mothership_lvo_ivt_mrs_dists_6     34752 non-null  float64
 53  mothership_lvo_ivt_mt_mrs_dists_0  34752 non-null  float64
 54  mothership_lvo_ivt_mt_mrs_dists_1  34752 non-null  float64
 55  mothership_lvo_ivt_mt_mrs_dists_2  34752 non-null  float64
 56  mothership_lvo_ivt_mt_mrs_dists_3  34752 non-null  float64
 57  mothership_lvo_ivt_mt_mrs_dists_4  34752 non-null  float64
 58  mothership_lvo_ivt_mt_mrs_dists_5  34752 non-null  float64
 59  mothership_lvo_ivt_mt_mrs_dists_6  34752 non-null  float64
 60  mothership_lvo_mt_mrs_dists_0      34752 non-null  float64
 61  mothership_lvo_mt_mrs_dists_1      34752 non-null  float64
 62  mothership_lvo_mt_mrs_dists_2      34752 non-null  float64
 63  mothership_lvo_mt_mrs_dists_3      34752 non-null  float64
 64  mothership_lvo_mt_mrs_dists_4      34752 non-null  float64
 65  mothership_lvo_mt_mrs_dists_5      34752 non-null  float64
 66  mothership_lvo_mt_mrs_dists_6      34752 non-null  float64
dtypes: bool(1), float64(63), object(3)
memory usage: 17.8+ MB

mRS distributions#

Load in admissions data#

admissions = pd.read_csv('./data/lsoa_predicted_admissions.csv')
admissions.head(3)
lsoa11cd lsoa11nm msoa11cd msoa11nm country LSOA_predicted_admissions
0 E01000001 City of London 001A E02000001 City of London 001 E 1.569672
1 E01000002 City of London 001B E02000001 City of London 001 E 1.569672
2 E01000003 City of London 001C E02000001 City of London 001 E 1.569672
df_mrs = pd.merge(
    df_mrs.reset_index(), admissions[['lsoa11nm', 'LSOA_predicted_admissions']],
    left_on='LSOA', right_on='lsoa11nm', how='left'
)

Make non-cumulative mRS distributions#

cols_to_combine = [c for c in df_mrs.columns if 'dist' in c]
# Remove repeats from all the mRS bands:
cols_each_scen = sorted(list(set(['_'.join(c.split('_')[:-1]) for c in cols_to_combine])))
cols_each_scen
['drip_ship_lvo_ivt_mrs_dists',
 'drip_ship_lvo_ivt_mt_mrs_dists',
 'drip_ship_lvo_mt_mrs_dists',
 'drip_ship_nlvo_ivt_mrs_dists',
 'mothership_lvo_ivt_mrs_dists',
 'mothership_lvo_ivt_mt_mrs_dists',
 'mothership_lvo_mt_mrs_dists',
 'mothership_nlvo_ivt_mrs_dists']
# Make non-cumulative mRS distributions:
for c in cols_each_scen:
    cols_cumsum = [f'{c}_{i}' for i in range(7)]
    cols_noncum = [f'{c}_noncum_{i}' for i in range(7)]

    new_data = df_mrs[cols_cumsum].copy()
    # Take the difference between mRS bands:
    new_data = np.diff(new_data, prepend=0.0, axis=1)
    # Round the values:
    new_data = np.round(new_data, 5)
    # Store:
    df_mrs[cols_noncum] = new_data

Import reference no-treatment data#

mrs_dists, mrs_dists_notes = (
    stroke_outcome.outcome_utilities.import_mrs_dists_from_file())
mrs_dists
mRS<=0 mRS<=1 mRS<=2 mRS<=3 mRS<=4 mRS<=5 mRS<=6
Stroke type
pre_stroke_nlvo 0.583 0.746 0.850 0.951 0.993 1.000 1
pre_stroke_lvo 0.408 0.552 0.672 0.838 0.956 1.000 1
no_treatment_lvo 0.050 0.129 0.265 0.429 0.676 0.811 1
no_treatment_nlvo 0.198 0.460 0.580 0.708 0.856 0.918 1
no_effect_nlvo_ivt_deaths 0.196 0.455 0.574 0.701 0.847 0.908 1
no_effect_lvo_ivt_deaths 0.048 0.124 0.255 0.414 0.653 0.783 1
no_effect_lvo_mt_deaths 0.048 0.124 0.255 0.412 0.649 0.779 1
t0_treatment_nlvo_ivt 0.445 0.642 0.752 0.862 0.941 0.967 1
t0_treatment_lvo_ivt 0.140 0.233 0.361 0.522 0.730 0.838 1
t0_treatment_lvo_mt 0.306 0.429 0.548 0.707 0.851 0.915 1
mrs_dist_nlvo_no_treatment = mrs_dists.loc['no_treatment_nlvo'].values
mrs_dist_lvo_no_treatment = mrs_dists.loc['no_treatment_lvo'].values

mrs_dist_nlvo_no_treatment_noncum = np.diff(mrs_dist_nlvo_no_treatment, prepend=0.0)
mrs_dist_lvo_no_treatment_noncum = np.diff(mrs_dist_lvo_no_treatment, prepend=0.0)

Combine patient cohorts#

Combine LVO groups:

for model_name in ['drip_ship', 'mothership']:
    # New column names for non-cumulative and cumulative probabilities:
    cols_noncum = [f'{model_name}_lvo_mix_mrs_dists_noncum_{i}' for i in range(7)]
    cols_cum = [f'{model_name}_lvo_mix_mrs_dists_{i}' for i in range(7)]

    # Column names of existing data:
    cols_lvo_ivt = [f'{model_name}_lvo_ivt_mrs_dists_noncum_{i}' for i in range(7)]
    cols_lvo_ivt_mt = [f'{model_name}_lvo_ivt_mt_mrs_dists_noncum_{i}' for i in range(7)]
    cols_lvo_mt = [f'{model_name}_lvo_mt_mrs_dists_noncum_{i}' for i in range(7)]
    
    # Weighted sum:
    df_mrs[cols_noncum] = (
        (df_mrs[cols_lvo_ivt].values * proportions['lvo_ivt_only']) +
        (df_mrs[cols_lvo_ivt_mt].values * proportions['lvo_ivt_mt']) +
        (df_mrs[cols_lvo_mt].values * proportions['lvo_mt_only'])
    )
    # Remove the proportion of non-LVO strokes:
    df_mrs[cols_noncum] = df_mrs[cols_noncum] / prop_lvo_treated
    
    # Convert to cumulative probabilities:
    df_mrs[cols_cum] = np.cumsum(df_mrs[cols_noncum], axis=1)

    # Round the results:
    df_mrs[cols_noncum] = np.round(df_mrs[cols_noncum], 5)
    df_mrs[cols_cum] = np.round(df_mrs[cols_cum], 5)

Weighted treated ischaemic population.

We have no mRS distributions for the haemorrhagic strokes. We calculate the weighted population mRS distributions using the data that we do have, and then divide by the proportion of the population that is not haemorrhagic. This rescales the proportions so that all proportions excluding haemorrhagic sum to 1.

for model_name in ['drip_ship', 'mothership']:
    # New column names for non-cumulative and cumulative probabilities:
    cols_noncum = [f'{model_name}_weighted_treated_mrs_dists_noncum_{i}' for i in range(7)]
    cols_cum = [f'{model_name}_weighted_treated_mrs_dists_{i}' for i in range(7)]

    # Column names of existing data:
    cols_nlvo_ivt = [f'{model_name}_nlvo_ivt_mrs_dists_noncum_{i}' for i in range(7)]
    cols_lvo_ivt = [f'{model_name}_lvo_ivt_mrs_dists_noncum_{i}' for i in range(7)]
    cols_lvo_ivt_mt = [f'{model_name}_lvo_ivt_mt_mrs_dists_noncum_{i}' for i in range(7)]
    cols_lvo_mt = [f'{model_name}_lvo_mt_mrs_dists_noncum_{i}' for i in range(7)]
    
    # Weighted sum:
    df_mrs[cols_noncum] = (
        (df_mrs[cols_nlvo_ivt].values * proportions['nlvo_ivt']) +
        (df_mrs[cols_lvo_ivt].values * proportions['lvo_ivt_only']) +
        (df_mrs[cols_lvo_ivt_mt].values * proportions['lvo_ivt_mt']) +
        (df_mrs[cols_lvo_mt].values * proportions['lvo_mt_only'])
    )
    # Remove the proportion of haemorrhagic strokes:
    df_mrs[cols_noncum] = df_mrs[cols_noncum] / prop_ischaemic_treated
    
    # Convert to cumulative probabilities:
    df_mrs[cols_cum] = np.cumsum(df_mrs[cols_noncum], axis=1)
    
    # Round the results:
    df_mrs[cols_noncum] = np.round(df_mrs[cols_noncum], 5)
    df_mrs[cols_cum] = np.round(df_mrs[cols_cum], 5)

Weighted total ischaemic population.

We have no mRS distributions for the haemorrhagic strokes. We calculate the weighted population mRS distributions using the data that we do have, and then divide by the proportion of the population that is not haemorrhagic. This rescales the proportions so that all proportions excluding haemorrhagic sum to 1.

for model_name in ['drip_ship', 'mothership']:
    # New column names for non-cumulative and cumulative probabilities:
    cols_noncum = [f'{model_name}_weighted_mrs_dists_noncum_{i}' for i in range(7)]
    cols_cum = [f'{model_name}_weighted_mrs_dists_{i}' for i in range(7)]

    # Column names of existing data:
    cols_nlvo_ivt = [f'{model_name}_nlvo_ivt_mrs_dists_noncum_{i}' for i in range(7)]
    cols_lvo_ivt = [f'{model_name}_lvo_ivt_mrs_dists_noncum_{i}' for i in range(7)]
    cols_lvo_ivt_mt = [f'{model_name}_lvo_ivt_mt_mrs_dists_noncum_{i}' for i in range(7)]
    cols_lvo_mt = [f'{model_name}_lvo_mt_mrs_dists_noncum_{i}' for i in range(7)]
    
    # Weighted sum:
    df_mrs[cols_noncum] = (
        (df_mrs[cols_nlvo_ivt].values * proportions['nlvo_ivt']) +
        (df_mrs[cols_lvo_ivt].values * proportions['lvo_ivt_only']) +
        (df_mrs[cols_lvo_ivt_mt].values * proportions['lvo_ivt_mt']) +
        (df_mrs[cols_lvo_mt].values * proportions['lvo_mt_only']) +
        (mrs_dist_nlvo_no_treatment_noncum * proportions['nlvo_no_treatment']) +
        (mrs_dist_lvo_no_treatment_noncum * proportions['lvo_no_treatment'])
    )
    # Remove the proportion of haemorrhagic strokes:
    df_mrs[cols_noncum] = df_mrs[cols_noncum] / prop_ischaemic
    
    # Convert to cumulative probabilities:
    df_mrs[cols_cum] = np.cumsum(df_mrs[cols_noncum], axis=1)
    
    # Round the results:
    df_mrs[cols_noncum] = np.round(df_mrs[cols_noncum], 5)
    df_mrs[cols_cum] = np.round(df_mrs[cols_cum], 5)

Average mRS distributions by admissions#

# Remove repeats from all the mRS bands:
cols_each_scen = sorted(list(set(
    [c.split('mrs_dist')[0] + 'mrs_dist' for c in df_mrs.columns if 'mrs_dist' in c]
)))
cols_each_scen
['drip_ship_lvo_ivt_mrs_dist',
 'drip_ship_lvo_ivt_mt_mrs_dist',
 'drip_ship_lvo_mix_mrs_dist',
 'drip_ship_lvo_mt_mrs_dist',
 'drip_ship_nlvo_ivt_mrs_dist',
 'drip_ship_weighted_mrs_dist',
 'drip_ship_weighted_treated_mrs_dist',
 'mothership_lvo_ivt_mrs_dist',
 'mothership_lvo_ivt_mt_mrs_dist',
 'mothership_lvo_mix_mrs_dist',
 'mothership_lvo_mt_mrs_dist',
 'mothership_nlvo_ivt_mrs_dist',
 'mothership_weighted_mrs_dist',
 'mothership_weighted_treated_mrs_dist']

Only make national statistics for areas where mothership and drip and ship are different:

mask = df_mrs['mt_transfer_required']
from statsmodels.stats.weightstats import DescrStatsW  # for mRS dist stats
df_mrs_national = pd.DataFrame()
df_mrs_national_noncum = pd.DataFrame()
df_mrs_national_std = pd.DataFrame()

# Stats:
for c, col in enumerate(cols_each_scen):
    cols_here = [c for c in df_mrs.columns if ((c.startswith(col)) & ('noncum' in c))]

    # Split list of values into one column per mRS band
    # and keep one row per LSOA.
    vals = df_mrs.loc[mask, cols_here].copy()

    # Create stats from these data:
    weighted_stats = DescrStatsW(vals, weights=df_mrs.loc[mask, 'LSOA_predicted_admissions'], ddof=0)
    # Means (one value per mRS):
    means = weighted_stats.mean
    # Standard deviations (one value per mRS):
    stds = weighted_stats.std
    # Cumulative probability from the mean bins:
    cumulatives = np.cumsum(means)
    
    # Store the data in these columns:
    cols_cumulative = [f'mRS<={i}' for i in range(7)]
    cols_noncum = [f'mRS={i}' for i in range(7)]

    # Store in results df. Round the values to 5 decimal places.
    val = col.split('_mrs_dist')[0]
    df_mrs_national_noncum.loc[val, cols_noncum] = np.round(means, 5)
    df_mrs_national.loc[val, cols_cumulative] = np.round(cumulatives, 5)
    df_mrs_national_std.loc[val, cols_noncum] = np.round(stds, 5)
df_mrs_national
mRS<=0 mRS<=1 mRS<=2 mRS<=3 mRS<=4 mRS<=5 mRS<=6
drip_ship_lvo_ivt 0.10356 0.19544 0.32788 0.49012 0.70857 0.82316 1.0
drip_ship_lvo_ivt_mt 0.11472 0.22605 0.37176 0.54453 0.75047 0.85084 1.0
drip_ship_lvo_mix 0.11382 0.22365 0.36835 0.54031 0.74723 0.84869 1.0
drip_ship_lvo_mt 0.11449 0.22589 0.37170 0.54455 0.75052 0.85086 1.0
drip_ship_nlvo_ivt 0.36134 0.58906 0.70508 0.82416 0.92123 0.95515 1.0
drip_ship_weighted 0.18250 0.39015 0.51547 0.65399 0.81988 0.89575 1.0
drip_ship_weighted_treated 0.23655 0.40482 0.53531 0.68105 0.83350 0.90148 1.0
mothership_lvo_ivt 0.09705 0.18809 0.32101 0.48329 0.70384 0.81982 1.0
mothership_lvo_ivt_mt 0.15523 0.27670 0.42080 0.59378 0.78327 0.87247 1.0
mothership_lvo_mix 0.15072 0.26984 0.41306 0.58522 0.77711 0.86839 1.0
mothership_lvo_mt 0.15523 0.27670 0.42080 0.59378 0.78327 0.87247 1.0
mothership_nlvo_ivt 0.34442 0.57736 0.69431 0.81494 0.91617 0.95206 1.0
mothership_weighted 0.18504 0.39450 0.51975 0.65849 0.82301 0.89784 1.0
mothership_weighted_treated 0.24676 0.42231 0.55251 0.69911 0.84606 0.90988 1.0
df_mrs_national_noncum
mRS=0 mRS=1 mRS=2 mRS=3 mRS=4 mRS=5 mRS=6
drip_ship_lvo_ivt 0.10356 0.09188 0.13244 0.16224 0.21845 0.11459 0.17684
drip_ship_lvo_ivt_mt 0.11472 0.11133 0.14571 0.17277 0.20594 0.10037 0.14916
drip_ship_lvo_mix 0.11382 0.10983 0.14470 0.17197 0.20692 0.10146 0.15131
drip_ship_lvo_mt 0.11449 0.11139 0.14582 0.17284 0.20597 0.10034 0.14914
drip_ship_nlvo_ivt 0.36134 0.22771 0.11603 0.11907 0.09707 0.03393 0.04485
drip_ship_weighted 0.18250 0.20765 0.12532 0.13852 0.16589 0.07586 0.10425
drip_ship_weighted_treated 0.23655 0.16828 0.13048 0.14574 0.15245 0.06798 0.09852
mothership_lvo_ivt 0.09705 0.09104 0.13293 0.16228 0.22054 0.11599 0.18018
mothership_lvo_ivt_mt 0.15523 0.12147 0.14409 0.17298 0.18949 0.08921 0.12753
mothership_lvo_mix 0.15072 0.11911 0.14323 0.17215 0.19189 0.09128 0.13161
mothership_lvo_mt 0.15523 0.12147 0.14409 0.17298 0.18949 0.08921 0.12753
mothership_nlvo_ivt 0.34442 0.23294 0.11695 0.12062 0.10124 0.03589 0.04794
mothership_weighted 0.18504 0.20946 0.12525 0.13873 0.16452 0.07483 0.10216
mothership_weighted_treated 0.24676 0.17555 0.13020 0.14660 0.14695 0.06382 0.09012
df_mrs_national_std
mRS=0 mRS=1 mRS=2 mRS=3 mRS=4 mRS=5 mRS=6
drip_ship_lvo_ivt 0.00262 0.00029 0.00022 0.00003 0.00083 0.00055 0.00129
drip_ship_lvo_ivt_mt 0.00983 0.00399 0.00143 0.00129 0.00452 0.00355 0.00729
drip_ship_lvo_mix 0.00924 0.00365 0.00118 0.00111 0.00422 0.00329 0.00677
drip_ship_lvo_mt 0.01037 0.00373 0.00054 0.00080 0.00460 0.00347 0.00723
drip_ship_nlvo_ivt 0.00667 0.00215 0.00039 0.00064 0.00160 0.00074 0.00116
drip_ship_weighted 0.00180 0.00037 0.00014 0.00013 0.00067 0.00047 0.00094
drip_ship_weighted_treated 0.00723 0.00150 0.00058 0.00052 0.00269 0.00191 0.00379
mothership_lvo_ivt 0.00568 0.00090 0.00035 0.00004 0.00188 0.00128 0.00309
mothership_lvo_ivt_mt 0.01227 0.00250 0.00093 0.00032 0.00475 0.00307 0.00577
mothership_lvo_mix 0.01176 0.00237 0.00089 0.00030 0.00452 0.00293 0.00557
mothership_lvo_mt 0.01227 0.00250 0.00093 0.00032 0.00475 0.00307 0.00577
mothership_nlvo_ivt 0.01520 0.00444 0.00075 0.00131 0.00387 0.00187 0.00297
mothership_weighted 0.00335 0.00026 0.00020 0.00019 0.00104 0.00060 0.00107
mothership_weighted_treated 0.01346 0.00103 0.00082 0.00078 0.00420 0.00240 0.00428

Errors for weighted combinations#

Redo the standard deviations to properly propagate the errors from the separate cohorts.

LVO mix:

drip_ship_lvo_stds_before = df_mrs_national_std.loc['drip_ship_lvo_mix'].copy()
mothership_lvo_stds_before = df_mrs_national_std.loc['mothership_lvo_mix'].copy()
stds_to_combine = ['lvo_ivt', 'lvo_mt', 'lvo_ivt_mt']

for model_name in ['drip_ship', 'mothership']:
    # New column names for std:
    ind = f'{model_name}_lvo_mix'

    # Column names of existing data:
    ind_lvo_ivt = f'{model_name}_lvo_ivt'
    ind_lvo_ivt_mt = f'{model_name}_lvo_ivt_mt'
    ind_lvo_mt = f'{model_name}_lvo_mt'
    
    # Weighted sum:
    df_mrs_national_std.loc[ind] = np.sqrt(
        (df_mrs_national_std.loc[ind_lvo_ivt].values * (proportions['lvo_ivt_only']  / prop_lvo_treated))**2.0 +
        (df_mrs_national_std.loc[ind_lvo_ivt_mt].values * (proportions['lvo_ivt_mt']  / prop_lvo_treated))**2.0 +
        (df_mrs_national_std.loc[ind_lvo_mt].values * (proportions['lvo_mt_only']  / prop_lvo_treated))**2.0
    )

    # Round to 5 decimal places:
    df_mrs_national_std.loc[ind] = np.round(df_mrs_national_std.loc[ind], 5)
pd.DataFrame(
    np.stack((
        drip_ship_lvo_stds_before,
        df_mrs_national_std.loc['drip_ship_lvo_mix'],
        mothership_lvo_stds_before,
        df_mrs_national_std.loc['mothership_lvo_mix']
    ), axis=-1),
    columns=['Drip and ship before', 'Drip and ship after', 'Mothership before', 'Mothership after']
)
Drip and ship before Drip and ship after Mothership before Mothership after
0 0.00924 0.00784 0.01176 0.00978
1 0.00365 0.00317 0.00237 0.00199
2 0.00118 0.00112 0.00089 0.00074
3 0.00111 0.00102 0.00030 0.00025
4 0.00422 0.00360 0.00452 0.00378
5 0.00329 0.00283 0.00293 0.00245
6 0.00677 0.00580 0.00557 0.00460

Treated population mix:

drip_ship_weighted_treated_stds_before = df_mrs_national_std.loc['drip_ship_weighted_treated'].copy()
mothership_weighted_treated_stds_before = df_mrs_national_std.loc['mothership_weighted_treated'].copy()
p = prop_ischaemic_treated

for model_name in ['drip_ship', 'mothership']:
    # New column names for non-cumulative and cumulative probabilities:
    ind = f'{model_name}_weighted_treated'

    # Column names of existing data:
    ind_nlvo_ivt = f'{model_name}_nlvo_ivt'
    ind_lvo_ivt = f'{model_name}_lvo_ivt'
    ind_lvo_ivt_mt = f'{model_name}_lvo_ivt_mt'
    ind_lvo_mt = f'{model_name}_lvo_mt'
    
    # Weighted sum:
    df_mrs_national_std.loc[ind] = np.sqrt(
        (df_mrs_national_std.loc[ind_nlvo_ivt].values * (proportions['nlvo_ivt'] / p))**2.0 +
        (df_mrs_national_std.loc[ind_lvo_ivt].values * (proportions['lvo_ivt_only'] / p))**2.0 +
        (df_mrs_national_std.loc[ind_lvo_ivt_mt].values * (proportions['lvo_ivt_mt'] / p))**2.0 +
        (df_mrs_national_std.loc[ind_lvo_mt].values * (proportions['lvo_mt_only'] / p))**2.0
    )
    
    # Round to 5 decimal places:
    df_mrs_national_std.loc[ind] = np.round(df_mrs_national_std.loc[ind], 5)
pd.DataFrame(
    np.stack((
        drip_ship_weighted_treated_stds_before,
        df_mrs_national_std.loc['drip_ship_weighted_treated'],
        mothership_weighted_treated_stds_before,
        df_mrs_national_std.loc['mothership_weighted_treated']
    ), axis=-1),
    columns=['Drip and ship before', 'Drip and ship after', 'Mothership before', 'Mothership after']
)    
Drip and ship before Drip and ship after Mothership before Mothership after
0 0.00723 0.00515 0.01346 0.00901
1 0.00150 0.00192 0.00103 0.00242
2 0.00058 0.00060 0.00082 0.00053
3 0.00052 0.00060 0.00078 0.00066
4 0.00269 0.00198 0.00420 0.00271
5 0.00191 0.00147 0.00240 0.00154
6 0.00379 0.00298 0.00428 0.00275

Total ischaemic population mix:

drip_ship_weighted_stds_before = df_mrs_national_std.loc['drip_ship_weighted'].copy()
mothership_weighted_stds_before = df_mrs_national_std.loc['mothership_weighted'].copy()
p = prop_ischaemic

for model_name in ['drip_ship', 'mothership']:
    # New column names for non-cumulative and cumulative probabilities:
    ind = f'{model_name}_weighted'

    # Column names of existing data:
    ind_nlvo_ivt = f'{model_name}_nlvo_ivt'
    ind_lvo_ivt = f'{model_name}_lvo_ivt'
    ind_lvo_ivt_mt = f'{model_name}_lvo_ivt_mt'
    ind_lvo_mt = f'{model_name}_lvo_mt'
    
    # Weighted sum:
    df_mrs_national_std.loc[ind] = np.sqrt(
        (df_mrs_national_std.loc[ind_nlvo_ivt].values * (proportions['nlvo_ivt'] / p))**2.0 +
        (df_mrs_national_std.loc[ind_lvo_ivt].values * (proportions['lvo_ivt_only'] / p))**2.0 +
        (df_mrs_national_std.loc[ind_lvo_ivt_mt].values * (proportions['lvo_ivt_mt'] / p))**2.0 +
        (df_mrs_national_std.loc[ind_lvo_mt].values * (proportions['lvo_mt_only'] / p))**2.0
    )
    
    # Round to 5 decimal places:
    df_mrs_national_std.loc[ind] = np.round(df_mrs_national_std.loc[ind], 5)
pd.DataFrame(
    np.stack((
        drip_ship_weighted_stds_before,
        df_mrs_national_std.loc['drip_ship_weighted'],
        mothership_weighted_stds_before,
        df_mrs_national_std.loc['mothership_weighted']
    ), axis=-1),
    columns=['Drip and ship before', 'Drip and ship after', 'Mothership before', 'Mothership after']
)    
Drip and ship before Drip and ship after Mothership before Mothership after
0 0.00180 0.00128 0.00335 0.00224
1 0.00037 0.00048 0.00026 0.00060
2 0.00014 0.00015 0.00020 0.00013
3 0.00013 0.00015 0.00019 0.00016
4 0.00067 0.00049 0.00104 0.00067
5 0.00047 0.00037 0.00060 0.00038
6 0.00094 0.00074 0.00107 0.00068

Save results#

# Save to file:
df_mrs.to_csv(os.path.join(dir_output, 'cohort_mrs_dists_weighted.csv'))
# Save to file:
df_mrs_national.to_csv(os.path.join(dir_output, 'cohort_mrs_dists_weighted_national.csv'))
df_mrs_national_noncum.to_csv(os.path.join(dir_output, 'cohort_mrs_dists_weighted_national_noncum.csv'))
df_mrs_national_std.to_csv(os.path.join(dir_output, 'cohort_mrs_dists_weighted_national_std.csv'))

Conclusion#

We have calculated the mRS distributions for mixed cohorts of patients and for the average across England and Wales.