Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Analysis of expanding HCW by cadre #1415

Open
wants to merge 219 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
219 commits
Select commit Hold shift + click to select a range
5aae8ef
try to add one scenario of expanding hcw
BinglingICL Jul 5, 2024
146631e
try to add the scenario script
BinglingICL Jul 5, 2024
7b09c1b
todo
BinglingICL Jul 5, 2024
75b88fc
input scenario data for increasing Clinical and Pharmacy cadres
BinglingICL Jul 6, 2024
2a52eaa
input scenario data for increasing Clinical and Pharmacy cadres
BinglingICL Jul 6, 2024
ac6e5ef
update the scenario script
BinglingICL Jul 6, 2024
1aa232a
recover the 'custom' sheet in the resource file to fix test failure
BinglingICL Jul 7, 2024
db6c145
update the scenario file
BinglingICL Jul 7, 2024
a7bf52b
update comments
BinglingICL Jul 7, 2024
825535e
update baseline scenario
BinglingICL Jul 10, 2024
6d44efc
Reduce the running period to 2010-2030
BinglingICL Jul 10, 2024
12cb85d
try create scenarios given a budget
BinglingICL Jul 11, 2024
9fda127
update the selection of scenarios
BinglingICL Jul 12, 2024
55c47d2
rename file
BinglingICL Jul 12, 2024
246e64e
reduce individual increase to 4 options per cadre
BinglingICL Jul 12, 2024
71cb109
reduce individual increase to 3 options per cadre
BinglingICL Jul 12, 2024
cdb1d9f
try increasing the individual increase of each cadre into 6 options
BinglingICL Jul 15, 2024
cee37a6
update todo
BinglingICL Jul 15, 2024
ba0b654
try increasing the individual increase of each cadre into 11 options
BinglingICL Jul 16, 2024
66ef671
calculate minute salary per cadre per level
BinglingICL Jul 17, 2024
28b31e8
create parameters for the HR expansion function
BinglingICL Jul 17, 2024
b4c32ae
design steps for the HR expansion function
BinglingICL Jul 17, 2024
9122524
update steps
BinglingICL Jul 17, 2024
8395512
add todo
BinglingICL Jul 17, 2024
ddb4602
create hr minute salary data
BinglingICL Jul 18, 2024
f5e2196
write the hr expansion function
BinglingICL Jul 18, 2024
937d33d
update the minute salary file
BinglingICL Jul 18, 2024
71dc92c
save the minute salary data
BinglingICL Jul 18, 2024
50df28a
calculate the current cost distribution of the four cadres
BinglingICL Aug 5, 2024
232b2ab
create the resource file for hr expansion scenarios base on fractions…
BinglingICL Aug 5, 2024
9e90e83
update resource file
BinglingICL Aug 5, 2024
0f44842
update scenario file
BinglingICL Aug 5, 2024
f3bbaa6
todo in test_healthsystem
BinglingICL Aug 5, 2024
1cd54e6
Merge branch 'refs/heads/master' into bs/expand_hcw
BinglingICL Aug 5, 2024
fece9ac
clean the data preparation file
BinglingICL Aug 5, 2024
f107449
fix checks failure
BinglingICL Aug 5, 2024
bf2bcea
fix checks failure
BinglingICL Aug 5, 2024
8a14ec0
fix checks failure
BinglingICL Aug 5, 2024
9abbe43
fix checks failure
BinglingICL Aug 5, 2024
d1a7823
renaming the scenario file
BinglingICL Aug 5, 2024
97869b0
fix failing tests
BinglingICL Aug 5, 2024
c3d04d0
creat the test of the hr expansion function
BinglingICL Aug 6, 2024
bc6d429
calculate scale up factor outside healthsystem module
BinglingICL Aug 12, 2024
7dfc7f3
local run that takes 12 hours
BinglingICL Aug 13, 2024
4eb3b08
save and read pickle file
BinglingICL Aug 13, 2024
37f39e5
create logger for hr scale up factor
BinglingICL Aug 13, 2024
3b9ba9a
Revert "local run that takes 12 hours"
BinglingICL Aug 13, 2024
f244f70
update the scenario script
BinglingICL Aug 14, 2024
4cac903
a run for only two scenarios
BinglingICL Aug 16, 2024
fde641e
scale to effective capabilities
BinglingICL Aug 19, 2024
90d590f
rename file
BinglingICL Aug 19, 2024
3dcd2d9
rename long run class in scenario file
BinglingICL Aug 19, 2024
51883c1
update test
BinglingICL Aug 19, 2024
74d8c62
initiate the analysis script - learn from Tim's branch 1414
BinglingICL Aug 20, 2024
9e047b1
extract more results
BinglingICL Aug 20, 2024
d14599c
initial plots and todo
BinglingICL Aug 20, 2024
708ef84
change to 10 runs per draw
BinglingICL Aug 20, 2024
a1e25d3
fix failing checks
BinglingICL Aug 20, 2024
8cc937d
plot dalys by cause
BinglingICL Aug 21, 2024
c7a0a5a
get comparison results
BinglingICL Aug 21, 2024
bec9530
plot comparison results
BinglingICL Aug 21, 2024
9a5d6af
update logger format of scale up factors
BinglingICL Aug 22, 2024
c1741a7
check if scale to effective capabilities = True will change 2019 capa…
BinglingICL Aug 22, 2024
853abc6
Revert "update logger format of scale up factors"
BinglingICL Aug 22, 2024
fcb5b75
get hr scale up factors
BinglingICL Aug 22, 2024
025f018
get current hr count by cadre
BinglingICL Aug 22, 2024
40219f4
get hr salary and update scale up factors
BinglingICL Aug 22, 2024
c4a7898
get extra staff and extra cost
BinglingICL Aug 22, 2024
1ebd47e
mannual calculation of total cost and total staff counts for each yea…
BinglingICL Aug 23, 2024
d4d89e0
calculate total cost and staff counts by the end of target period
BinglingICL Aug 23, 2024
6e5f345
Calculate and plot ROI and CE
BinglingICL Aug 27, 2024
1e91132
fix failing checks and plot deaths averted
BinglingICL Aug 27, 2024
5d003d6
add todo
BinglingICL Aug 27, 2024
22483a0
prepare scenarios of fractions that reflect current cost distribution…
BinglingICL Aug 27, 2024
aae8d7b
instead of save and reload extra budget fractions data, try directly …
BinglingICL Aug 27, 2024
5726154
rename file
BinglingICL Aug 27, 2024
ec6332a
update todo list
BinglingICL Aug 27, 2024
d30f73c
update todo list
BinglingICL Aug 27, 2024
a9f4e55
temporarily fix param_names to be consistent with latest scenario run…
BinglingICL Aug 27, 2024
9784abd
delete unnecessary file
BinglingICL Aug 27, 2024
f36015e
fix failed checks
BinglingICL Aug 27, 2024
d205aa4
name logger elements consistently
BinglingICL Aug 28, 2024
d728c1e
update todo
BinglingICL Aug 28, 2024
ce07e94
update plot name
BinglingICL Aug 28, 2024
b0aec4f
update todo
BinglingICL Aug 28, 2024
c22495a
plot numbers of staff and budget
BinglingICL Aug 28, 2024
ef9e2c8
update todo
BinglingICL Aug 29, 2024
2d61433
update todo
BinglingICL Aug 29, 2024
54db97f
update todo
BinglingICL Aug 29, 2024
e2a9feb
turn up scale to effective capabilities
BinglingICL Sep 3, 2024
b9e310f
update the preparation file to also expand all other cadres
BinglingICL Sep 4, 2024
b366357
update the function to expand officer type
BinglingICL Sep 5, 2024
d7cced9
update the logger
BinglingICL Sep 5, 2024
1f003b0
update test
BinglingICL Sep 5, 2024
c856968
update scenario run settings
BinglingICL Sep 5, 2024
2899b02
change data type to fix json error
BinglingICL Sep 5, 2024
d735bd3
update logger
BinglingICL Sep 5, 2024
c5dcdc2
scale down minute salary when scale up to effective capabilities
BinglingICL Sep 5, 2024
460436d
update logger
BinglingICL Sep 5, 2024
e34a276
update scenario run file
BinglingICL Sep 5, 2024
f633fe6
Merge remote-tracking branch 'refs/remotes/origin/master' into bs/exp…
BinglingICL Sep 5, 2024
6ced85b
add comments in test
BinglingICL Sep 6, 2024
10e6f95
submit a run with 3 draws
BinglingICL Sep 6, 2024
d49e471
assert to make sure the input the officer types match the defined
BinglingICL Sep 7, 2024
96783c6
test minute salary scale down
BinglingICL Sep 7, 2024
8b938ca
add comment on creating alternative scenarios
BinglingICL Sep 11, 2024
8f12ad5
temporary update plots for 3 scenarios
BinglingICL Sep 12, 2024
639ba14
distribute extra budget for Other group matching their cost distribution
BinglingICL Sep 12, 2024
5f41d02
Merge branch 'refs/heads/master' into bs/expand_hcw
BinglingICL Sep 12, 2024
72c9bc5
submit a run of all 33 scenarios
BinglingICL Sep 12, 2024
261c1e9
fix checks failure
BinglingICL Sep 12, 2024
4d45b46
plot extra staff by cadre
BinglingICL Sep 17, 2024
3b11f79
plot extra cost by cadre
BinglingICL Sep 18, 2024
ba2262b
initial plots for all scenarios
BinglingICL Sep 20, 2024
a558cc7
initial plots for all scenarios
BinglingICL Sep 20, 2024
494b6b8
update comments
BinglingICL Sep 23, 2024
45eebaf
fix failing checks
BinglingICL Sep 23, 2024
78dcb80
add scenario settings with historical scaling from 2019 to 2024 and e…
BinglingICL Sep 23, 2024
f650a2e
annotate bar plot for DALYs averted
BinglingICL Sep 24, 2024
587cdb1
plot for treatment counts
BinglingICL Sep 25, 2024
2311386
update scenario colors
BinglingICL Sep 26, 2024
116154c
plot yearly dalys and staff
BinglingICL Sep 26, 2024
cc5db6f
adjust figsize
BinglingICL Sep 26, 2024
3327b2c
reverse legend order
BinglingICL Sep 26, 2024
5c52605
minor ajdust
BinglingICL Sep 26, 2024
db27d5a
update scenario names
BinglingICL Oct 2, 2024
15a69a8
try plot 3D plots using 4D data
BinglingICL Oct 2, 2024
2241d46
update the 3D plot
BinglingICL Oct 4, 2024
eb9bac2
try multiple linear regression
BinglingICL Oct 4, 2024
7f4cf85
try extract more results and plot to understand the results
BinglingICL Oct 7, 2024
2fcb3c4
anova analysis and more plot
BinglingICL Oct 7, 2024
7b71b5e
plot never ran appts and hcw time gap/needed to run those appts
BinglingICL Oct 9, 2024
ac18fb5
update data prepare file
BinglingICL Oct 10, 2024
b569d71
plot more and delete some
BinglingICL Oct 10, 2024
96a072c
plot more never ran appts results
BinglingICL Oct 11, 2024
2b03be0
check summary logger Capacity
BinglingICL Oct 15, 2024
27d5404
plot never ran appts info
BinglingICL Oct 16, 2024
0ebfd12
minor formatting
BinglingICL Oct 16, 2024
a59f29f
extract fraction of hcw time used
BinglingICL Oct 16, 2024
8c98f0c
plot fraction of hcw time used
BinglingICL Oct 17, 2024
e85cae0
extract and plot results of hcw time by cadre and treatment
BinglingICL Oct 19, 2024
7374968
minor update
BinglingICL Oct 20, 2024
0d5611f
plot time used increased of C + P scenario
BinglingICL Oct 20, 2024
b466dc0
more plots of time used increased of C + P scenario
BinglingICL Oct 21, 2024
5e2ab06
more plots
BinglingICL Oct 21, 2024
6e68e32
comment results and plots, which may be less relevant
BinglingICL Oct 22, 2024
50338c5
reformat
BinglingICL Oct 22, 2024
8d45f0b
add todo for new loggers
BinglingICL Oct 22, 2024
51fe063
Merge remote-tracking branch 'refs/remotes/origin/master' into bs/exp…
BinglingICL Oct 22, 2024
3ca37a2
fix failing checks
BinglingICL Oct 22, 2024
411a256
prepare the "better scenario" indicated by never ran services cost gap
BinglingICL Oct 22, 2024
c55076a
undo the changes for historical scaling
BinglingICL Oct 22, 2024
62e5f72
to test the "best" scenario
BinglingICL Oct 22, 2024
603a480
fix series have no columns
BinglingICL Oct 22, 2024
a7e748b
fix the issue of running only one scenario
BinglingICL Oct 23, 2024
f189f17
try add suumary logger of fraction of time used by officer, level and…
BinglingICL Oct 24, 2024
30261f9
add fraction of time used by officer, level and district to summary c…
BinglingICL Oct 24, 2024
1df79e5
try add summary logger of appt num by appt and facility id
BinglingICL Oct 24, 2024
b17b774
modify summary logger of appt num by appt and facility id
BinglingICL Oct 24, 2024
d231bdb
modify summary logger of appt num by appt and facility id
BinglingICL Oct 24, 2024
77e26ab
a possible issue
BinglingICL Oct 24, 2024
d73a6e9
add summary logger of fraction of time used by officer district
BinglingICL Oct 24, 2024
83b0504
try fixing error of non-usual facilities
BinglingICL Oct 25, 2024
ce98147
add a small comment on rescaling capabilities
BinglingICL Oct 25, 2024
4f6583e
add todo tasks for RescalingHRCapabilities_ByDistrict
BinglingICL Oct 25, 2024
2f92ddc
plots for representative scenarios inc. the gap allocation
BinglingICL Oct 28, 2024
4a1923a
update comments
BinglingICL Oct 28, 2024
1794516
recover the plot of treatments, service demand, etc.
BinglingICL Oct 28, 2024
45b0d16
plots against current allocation scenario
BinglingICL Oct 28, 2024
9cc5220
Revert "plots against current allocation scenario"
BinglingICL Oct 28, 2024
6c32a78
minor reformat
BinglingICL Oct 28, 2024
8eb06ce
calculate time used
BinglingICL Oct 29, 2024
8439283
format scenario grouping and coloring
BinglingICL Oct 30, 2024
cfb29b6
format scenario grouping and coloring
BinglingICL Oct 30, 2024
0345754
plot for time info
BinglingICL Oct 30, 2024
23e485c
plot for CNP permutation scenarios
BinglingICL Nov 3, 2024
3b270d5
log the capabilities
BinglingICL Nov 5, 2024
d4f18bd
comment and uncomment some lines
BinglingICL Nov 6, 2024
3da4a00
no need to log the year of scale up in HRH expansion HSI
BinglingICL Nov 7, 2024
26a9cd2
turn on historical scaling for years 2020-2024
BinglingICL Nov 7, 2024
117a916
recover the scaling factors in historical scaling for years 2020-2024
BinglingICL Nov 7, 2024
ad03056
fix failing checks
BinglingICL Nov 7, 2024
ff698d1
fix failing checks
BinglingICL Nov 7, 2024
321a40b
update scenario run settings
BinglingICL Nov 7, 2024
ef3aae0
update scenario run settings and TBC
BinglingICL Nov 8, 2024
2b6e96e
update param_names
BinglingICL Nov 8, 2024
bc5f896
Merge remote-tracking branch 'refs/remotes/origin/master' into bs/exp…
BinglingICL Nov 11, 2024
780b9a8
update comment
BinglingICL Nov 11, 2024
0726246
format labels
BinglingICL Nov 12, 2024
e13b262
update scenario run settings and first run to test historical scaling…
BinglingICL Nov 12, 2024
8240fad
Merge remote-tracking branch 'refs/remotes/origin/master' into bs/exp…
BinglingICL Nov 12, 2024
c53f905
update 3D plot
BinglingICL Nov 14, 2024
7910145
correct type
BinglingICL Nov 19, 2024
f6bf449
update analysis file to run new results
BinglingICL Nov 19, 2024
11b7710
update comment of the "gap" strategies
BinglingICL Nov 19, 2024
4721844
Merge remote-tracking branch 'refs/remotes/origin/master' into bs/exp…
BinglingICL Nov 19, 2024
da8785c
update regression
BinglingICL Nov 21, 2024
71dc142
Merge remote-tracking branch 'refs/remotes/origin/master' into bs/exp…
BinglingICL Nov 21, 2024
84de376
set the "gap" allocation strategy for defaul + historical scaling
BinglingICL Nov 21, 2024
ca634f5
to run the "gap" allocation strategy for defaul + historical scaling
BinglingICL Nov 21, 2024
1d4077b
fix failing checks
BinglingICL Nov 21, 2024
4374217
run 5 more runs for baseline of baseline draws excl. "gap" strategy
BinglingICL Nov 29, 2024
e0eab5e
run for sensitivity analysis - baselines + no expansion - to get gap …
BinglingICL Nov 29, 2024
2c9f2ed
update the preparation file to incorporate historical scaling, which …
BinglingICL Dec 2, 2024
f513567
get the expected hrh increase rate
BinglingICL Dec 2, 2024
b968ffd
get yearly hrh count from logger
BinglingICL Dec 2, 2024
5670ed9
record the gap strategies for main and sensitivity analysis
BinglingICL Dec 6, 2024
2ad95cf
correct typo
BinglingICL Dec 6, 2024
bf1a3a1
rerun gap strategy for main analysis as the proportions has changed d…
BinglingICL Dec 6, 2024
c04e001
run all non-gap strategies for more budget
BinglingICL Dec 6, 2024
101f6ce
run all non-gap strategies for less budget
BinglingICL Dec 6, 2024
dacdd77
calculate average yearly increase rate per cadre during 2025-2034
BinglingICL Dec 11, 2024
b138a22
reduce runs per draw to 5
BinglingICL Dec 11, 2024
328e61c
Merge remote-tracking branch 'refs/remotes/origin/master' into bs/exp…
BinglingICL Dec 11, 2024
bd271c2
run default_cons for sensitivity analysis
BinglingICL Dec 11, 2024
c846eb6
update analysis file to include budget growth rate
BinglingICL Dec 12, 2024
a3c3010
Merge remote-tracking branch 'refs/remotes/origin/master' into bs/exp…
BinglingICL Dec 14, 2024
e0550bb
run max hs function for sensitivity analysis
BinglingICL Dec 14, 2024
25b8556
the 17th decimal of some cadre's minute salary has changed - due the …
BinglingICL Dec 14, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions resources/costing/Minute_Salary_HR.csv
Git LFS file not shown
3 changes: 3 additions & 0 deletions resources/costing/ResourceFile_Annual_Salary_Per_Cadre.csv
Git LFS file not shown

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
"""
We calculate the salary cost of current and funded plus HCW.
"""
import itertools
# import pickle
from pathlib import Path

import numpy as np
import pandas as pd

resourcefilepath = Path('./resources')

mfl = pd.read_csv(resourcefilepath / 'healthsystem' / 'organisation' / 'ResourceFile_Master_Facilities_List.csv')

hr_salary = pd.read_csv(resourcefilepath /
'costing' / 'ResourceFile_Annual_Salary_Per_Cadre.csv', index_col=False)
hr_salary_per_level = pd.read_excel(resourcefilepath /
'costing' / 'ResourceFile_Costing.xlsx', sheet_name='human_resources')
# as of 2019
hr_current = pd.read_csv(resourcefilepath /
'healthsystem' / 'human_resources' / 'actual' / 'ResourceFile_Daily_Capabilities.csv')
hr_established = pd.read_csv(resourcefilepath /
'healthsystem' / 'human_resources' / 'funded_plus' / 'ResourceFile_Daily_Capabilities.csv')
# for 2020-2024
historical_scaling = pd.read_excel(resourcefilepath /
'healthsystem' / 'human_resources' / 'scaling_capabilities' /
'ResourceFile_dynamic_HR_scaling.xlsx', sheet_name='historical_scaling'
).set_index('year')
integrated_historical_scaling = (
historical_scaling.loc[2020, 'dynamic_HR_scaling_factor'] *
historical_scaling.loc[2021, 'dynamic_HR_scaling_factor'] *
historical_scaling.loc[2022, 'dynamic_HR_scaling_factor'] *
historical_scaling.loc[2023, 'dynamic_HR_scaling_factor'] *
historical_scaling.loc[2024, 'dynamic_HR_scaling_factor']
)

# to get minute salary per cadre per level
Annual_PFT = hr_current.groupby(['Facility_Level', 'Officer_Category']).agg(
{'Total_Mins_Per_Day': 'sum', 'Staff_Count': 'sum'}).reset_index()
Annual_PFT['Annual_Mins_Per_Staff'] = 365.25 * Annual_PFT['Total_Mins_Per_Day']/Annual_PFT['Staff_Count']

# the hr salary by minute and facility id, as of 2019
Minute_Salary = Annual_PFT.merge(hr_salary, on=['Officer_Category'], how='outer')
Minute_Salary['Minute_Salary_USD'] = Minute_Salary['Annual_Salary_USD']/Minute_Salary['Annual_Mins_Per_Staff']
# store the minute salary by cadre and level
Minute_Salary_by_Cadre_Level = Minute_Salary[
['Facility_Level', 'Officer_Category', 'Minute_Salary_USD']
].copy().fillna(0.0)
Minute_Salary = Minute_Salary[['Facility_Level', 'Officer_Category', 'Minute_Salary_USD']].merge(
mfl[['Facility_Level', 'Facility_ID']], on=['Facility_Level'], how='outer'
)
Minute_Salary.drop(columns=['Facility_Level'], inplace=True)
Minute_Salary = Minute_Salary.fillna(0.0)
Minute_Salary.rename(columns={'Officer_Category': 'Officer_Type_Code'}, inplace=True)

Minute_Salary.to_csv(resourcefilepath / 'costing' / 'Minute_Salary_HR.csv', index=False)

# implement historical scaling to hr_current
hr_current['Total_Mins_Per_Day'] *= integrated_historical_scaling
hr_current['Staff_Count'] *= integrated_historical_scaling

# calculate the current cost distribution of all cadres, as of 2024
cadre_all = ['Clinical', 'DCSA', 'Nursing_and_Midwifery', 'Pharmacy',
'Dental', 'Laboratory', 'Mental', 'Nutrition', 'Radiography']
staff_count = hr_current.groupby('Officer_Category')['Staff_Count'].sum().reset_index()
staff_cost = staff_count.merge(hr_salary, on=['Officer_Category'], how='outer')
staff_cost['annual_cost'] = staff_cost['Staff_Count'] * staff_cost['Annual_Salary_USD']
staff_cost['cost_frac'] = (staff_cost['annual_cost'] / staff_cost['annual_cost'].sum())
assert abs(staff_cost.cost_frac.sum() - 1) < 1/1e8
staff_cost.set_index('Officer_Category', inplace=True)
staff_cost = staff_cost.reindex(index=cadre_all)

# No expansion scenario, or zero-extra-budget-fraction scenario, "s_0"
# Define the current cost fractions among all cadres as extra-budget-fraction scenario "s_1" \
# to be matched with Margherita's 4.2% scenario.
# Add in the scenario that is indicated by hcw cost gap distribution \
# resulted from never ran services in no expansion scenario, "s_2"
# Define all other scenarios so that the extra budget fraction of each cadre, \
# i.e., four main cadres and the "Other" cadre that groups up all other cadres, is the same (fair allocation)

cadre_group = ['Clinical', 'DCSA', 'Nursing_and_Midwifery', 'Pharmacy', 'Other'] # main cadres
other_group = ['Dental', 'Laboratory', 'Mental', 'Nutrition', 'Radiography']

# create scenarios
combination_list = ['s_0', 's_1', 's_2'] # the three special scenarios
for n in range(1, len(cadre_group)+1):
for subset in itertools.combinations(cadre_group, n):
combination_list.append(str(subset)) # other equal-fraction scenarios

# cadre groups to expand
cadre_to_expand = pd.DataFrame(index=cadre_group, columns=combination_list).fillna(0.0)
for c in cadre_group:
for i in cadre_to_expand.columns[3:]: # for all equal-fraction scenarios
if c in i:
cadre_to_expand.loc[c, i] = 1 # value 1 indicate the cadre group will be expanded

# prepare auxiliary dataframe for equal extra budget fractions scenarios
auxiliary = cadre_to_expand.copy()
for i in auxiliary.columns[3:]: # for all equal-fraction scenarios
auxiliary.loc[:, i] = auxiliary.loc[:, i] / auxiliary.loc[:, i].sum()
# for "gap" allocation strategy
# auxiliary.loc[:, 's_2'] = [0.4586, 0.0272, 0.3502, 0.1476, 0.0164] # without historical scaling; "default" settings
# auxiliary.loc[:, 's_2'] = [0.4314, 0.0214, 0.3701, 0.1406, 0.0365] # historical scaling + main settings
# auxiliary.loc[:, 's_2'] = [0.4314, 0.0214, 0.3701, 0.1406, 0.0365] # historical scaling + more_budget; same as above
# auxiliary.loc[:, 's_2'] = [0.4314, 0.0214, 0.3701, 0.1406, 0.0365] # historical scaling + less_budget; same as above
# auxiliary.loc[:, 's_2'] = [0.4252, 0.0261, 0.3752, 0.1362, 0.0373] # historical scaling + default_cons
auxiliary.loc[:, 's_2'] = [0.5133, 0.0085, 0.2501, 0.1551, 0.073] # historical scaling + max_hs_function

# define extra budget fracs for each cadre
extra_budget_fracs = pd.DataFrame(index=cadre_all, columns=combination_list)
assert (extra_budget_fracs.columns == auxiliary.columns).all()
assert (extra_budget_fracs.index[0:4] == auxiliary.index[0:4]).all()

extra_budget_fracs.loc[:, 's_0'] = 0
assert (staff_cost.index == extra_budget_fracs.index).all()
extra_budget_fracs.loc[:, 's_1'] = staff_cost.loc[:, 'cost_frac'].values

for i in extra_budget_fracs.columns[2:]:
for c in extra_budget_fracs.index:
if c in auxiliary.index: # the four main cadres
extra_budget_fracs.loc[c, i] = auxiliary.loc[c, i]
else: # the other 5 cadres
extra_budget_fracs.loc[c, i] = auxiliary.loc['Other', i] * (
staff_cost.loc[c, 'cost_frac'] / staff_cost.loc[staff_cost.index.isin(other_group), 'cost_frac'].sum()
) # current cost distribution among the 5 other cadres
# extra_budget_fracs.loc[c, i] = auxiliary.loc['Other', i] / 5 # equal fracs among the 5 other cadres

assert (abs(extra_budget_fracs.iloc[:, 1:len(extra_budget_fracs.columns)].sum(axis=0) - 1.0) < 1/1e10).all()

# rename scenarios
# make the scenario of equal fracs for all five cadre groups (i.e., the last column) to be s_3
simple_scenario_name = {extra_budget_fracs.columns[-1]: 's_3'}
for i in range(3, len(extra_budget_fracs.columns)-1):
simple_scenario_name[extra_budget_fracs.columns[i]] = 's_' + str(i+1) # name scenario from s_4
extra_budget_fracs.rename(columns=simple_scenario_name, inplace=True)

# reorder columns
col_order = ['s_' + str(i) for i in range(0, len(extra_budget_fracs.columns))]
assert len(col_order) == len(extra_budget_fracs.columns)
extra_budget_fracs = extra_budget_fracs.reindex(columns=col_order)


# calculate hr scale up factor for years 2020-2030 (10 years in total) outside the healthsystem module

def calculate_hr_scale_up_factor(extra_budget_frac, yr, scenario) -> pd.DataFrame:
"""This function calculates the yearly hr scale up factor for cadres for a year yr,
given a fraction of an extra budget allocated to each cadre and a yearly budget growth rate of 4.2%.
Parameter extra_budget_frac (list) is a list of 9 floats, representing the fractions.
Parameter yr (int) is a year between 2025 and 2035 (exclusive).
Parameter scenario (string) is a column name in the extra budget fractions resource file.
Output dataframe stores scale up factors and relevant for the year yr.
"""
# get data of previous year
prev_year = yr - 1
prev_data = scale_up_factor_dict[scenario][prev_year].copy()

# calculate and update scale_up_factor
prev_data['extra_budget_frac'] = extra_budget_frac
prev_data['extra_budget'] = 0.042 * prev_data.annual_cost.sum() * prev_data.extra_budget_frac
prev_data['extra_staff'] = prev_data.extra_budget / prev_data.Annual_Salary_USD
prev_data['scale_up_factor'] = (prev_data.Staff_Count + prev_data.extra_staff) / prev_data.Staff_Count

# store the updated data for the year yr
new_data = prev_data[['Annual_Salary_USD', 'scale_up_factor']].copy()
new_data['Staff_Count'] = prev_data.Staff_Count + prev_data.extra_staff
new_data['annual_cost'] = prev_data.annual_cost + prev_data.extra_budget

return new_data


# calculate scale up factors for all defined scenarios and years
staff_cost['scale_up_factor'] = 1
scale_up_factor_dict = {s: {y: {} for y in range(2025, 2035)} for s in extra_budget_fracs.columns}
for s in extra_budget_fracs.columns:
# for the initial/current year of 2024
scale_up_factor_dict[s][2024] = staff_cost.drop(columns='cost_frac').copy()
# for the years with scaled up hr
for y in range(2025, 2035):
scale_up_factor_dict[s][y] = calculate_hr_scale_up_factor(list(extra_budget_fracs[s]), y, s)

# get the total cost and staff count for each year between 2024-2034 and each scenario
total_cost = pd.DataFrame(index=range(2024, 2035), columns=extra_budget_fracs.columns)
total_staff = pd.DataFrame(index=range(2024, 2035), columns=extra_budget_fracs.columns)
for y in total_cost.index:
for s in extra_budget_fracs.columns:
total_cost.loc[y, s] = scale_up_factor_dict[s][y].annual_cost.sum()
total_staff.loc[y, s] = scale_up_factor_dict[s][y].Staff_Count.sum()

# check the total cost after 10 years are increased as expected
assert (
abs(total_cost.loc[2034, total_cost.columns[1:]] - (1 + 0.042) ** 10 * total_cost.loc[2024, 's_0']) < 1/1e6
).all()

# get the integrated scale up factors by the end of year 2034 and each scenario
integrated_scale_up_factor = pd.DataFrame(index=cadre_all, columns=total_cost.columns).fillna(1.0)
for s in total_cost.columns[1:]:
for yr in range(2025, 2035):
integrated_scale_up_factor.loc[:, s] = np.multiply(
integrated_scale_up_factor.loc[:, s].values,
scale_up_factor_dict[s][yr].loc[:, 'scale_up_factor'].values
)

# get the staff increase rate: 2034 vs 2025
hr_increase_rates_2034 = pd.DataFrame(integrated_scale_up_factor - 1.0)
hr_avg_yearly_increase_rate = pd.DataFrame(integrated_scale_up_factor**(1/10) - 1.0)

# Checked that for s_2, the integrated scale up factors of C/N/P cadres are comparable with shortage estimates from \
# She et al 2024: https://human-resources-health.biomedcentral.com/articles/10.1186/s12960-024-00949-2
# C: 2.21, N: 1.44, P: 4.14 vs C: 2.83, N: 1.57, P:6.37
# todo: This might provide a short-cut way (no simulation, but mathematical calculation) to calculate \
# an extra budget allocation scenario 's_2+' that is comparable with s_2.

# # save and read pickle file
# pickle_file_path = Path(resourcefilepath / 'healthsystem' / 'human_resources' / 'scaling_capabilities' /
# 'ResourceFile_HR_expansion_by_officer_type_yearly_scale_up_factors.pickle')
#
# with open(pickle_file_path, 'wb') as f:
# pickle.dump(scale_up_factor_dict, f)
#
# with open(pickle_file_path, 'rb') as f:
# x = pickle.load(f)
Loading
Loading