#!/usr/bin/env python
from utility_modules.get_parameters import get_params
from utility_modules.get_parameters import get_parse_params
from utility_modules.av_module import oop_av
import numpy as np
import pandas as pd
import pdb
[docs]class CostSharing:
# Borg singleton config
__shared_state = {}
def __init__(self, policy_params = None):
# implement the borg pattern
self.__dict__ = self.__shared_state
if policy_params != None:
gid_cost_sharing = policy_params['prem_sub']
gid_firm_behavior=policy_params['firm_behavior']
self.cost_sharing = get_params(gid_cost_sharing)
self.firm_behavior=get_parse_params(gid_firm_behavior)
self.elasticity=self.firm_behavior.AV_elasticity
av_sheet=get_params(policy_params['xc_admin_loading'])
self.silver_av=av_sheet[av_sheet['type']==6].av.min()
[docs] def set_year(self, curr_year):
"""
return slice of pertinant year
allows this to be reset at begining of each simulation year
"""
if curr_year not in self.cost_sharing.year.values:
return
else:
# subset to only values in designated year
self.cost_sharing_subset = self.cost_sharing[self.cost_sharing.year == curr_year]
self.cost_sharing_subset = self.cost_sharing_subset.reset_index()
self.cost_fpl_lower = self.cost_sharing_subset['fpl_lower'].tolist()
self.cost_fpl_upper = self.cost_sharing_subset['fpl_upper'].tolist()
self.max_oop_single = self.cost_sharing_subset[
'silver_oop_max_s'].tolist() # OOP for single as y-axis for interpolation
self.max_oop_family = self.cost_sharing_subset[
'silver_oop_max_f'].tolist() # OOP for family as y-axis for interpolation
self.silver_cs = self.cost_sharing_subset['cost_sharing'].tolist()
self.fpl_bracket=[self.cost_fpl_lower[0]]
self.cost_sharing_bracket=[]
self.oop_single_bracket=[]
self.oop_family_bracket=[]
for i in range(1,len(self.cost_fpl_lower)):
self.fpl_bracket=self.fpl_bracket+[self.cost_fpl_lower[i]]+[self.cost_fpl_lower[i]]
self.cost_sharing_bracket=self.cost_sharing_bracket+[self.silver_cs[i-1]]+[self.silver_cs[i-1]]
self.oop_single_bracket = self.oop_single_bracket + [self.max_oop_single[i - 1]] + [self.max_oop_single[i - 1]]
self.oop_family_bracket = self.oop_family_bracket + [self.max_oop_family[i - 1]] + [self.max_oop_family[i - 1]]
self.cost_sharing_bracket=self.cost_sharing_bracket+[self.silver_cs[-1]]
self.oop_single_bracket = self.oop_single_bracket + [self.max_oop_single[-1]]
self.oop_family_bracket = self.oop_family_bracket + [self.max_oop_family[-1]]
[docs] def oop_update(self, choice_table, pop_df):
"""
updates OOP for those on a silver plan with cost sharing subsidy values
assuming that pop_df has subsidy_elig column already
"""
#manifest constants: choices
people = ['adult_1', 'adult_2', 'child_1', 'child_2', 'adult_child_1', \
'adult_child_2', 'adult_child_3','adult_child_4']
people_indices = [0, 1, 2, 3, 4, 5, 6, 7]
# oop columns
oop_cols = ['oop0','oop2','oop2','oop3','oop4','oop5','oop6', 'oop7']
# temp pop_df: calculating for each person and each choice, max oop amount
temp_pop_df = pop_df
temp_pop_df['cost_sharing']=np.interp(temp_pop_df['fpl'],self.fpl_bracket,self.cost_sharing_bracket)
temp_pop_df['oop_single_max'] = np.interp(temp_pop_df['fpl'], self.fpl_bracket, self.oop_single_bracket)
temp_pop_df['oop_family_max'] = np.interp(temp_pop_df['fpl'], self.fpl_bracket, self.oop_family_bracket)
loc_ind_adult_child=np.where((temp_pop_df['person_type'] > 3) & (temp_pop_df['tax_dependent'] == 0))[0]
temp_pop_df.loc[loc_ind_adult_child,'cost_sharing']=np.interp(temp_pop_df.loc[loc_ind_adult_child,'ind_fpl'],self.fpl_bracket,self.cost_sharing_bracket)
temp_pop_df.loc[loc_ind_adult_child, 'oop_single_max'] = np.interp(temp_pop_df.loc[loc_ind_adult_child, 'ind_fpl'], self.fpl_bracket, self.oop_single_bracket)
temp_pop_df.loc[loc_ind_adult_child, 'oop_family_max'] = np.interp(temp_pop_df.loc[loc_ind_adult_child, 'ind_fpl'], self.fpl_bracket, self.oop_family_bracket)
# preparing for merging with choice table
cost_sharing_df =pd.pivot_table(temp_pop_df,index='hieu_id', columns='person_type', values=['cost_sharing','oop_single_max','oop_family_max'])
cost_sharing_df.columns = ['cost_sharing_' + str(i) for i in range(8)]+['oop_single_max_' + str(i) for i in range(8)]+['oop_family_max_' + str(i) for i in range(8)]
cost_sharing_df= cost_sharing_df.reset_index()
my_choices = pd.merge(choice_table, cost_sharing_df, on='hieu_id', how='left')
#my_choices.reset_index(drop=True, inplace=True)
##### NOT DOING FAMILY OOP YET ######
cost_sharing_columns = ['cost_sharing_' + str(i) for i in range(8)]
oop_single_columns = ['oop_single_max_' + str(i) for i in range(8)]
oop_family_columns = ['oop_family_max_' + str(i) for i in range(8)]
#adjust expenditure and count number of family members on silver(choice==6,subsidy_eligible and exclude tax_independent adult_child),also calculate their oop_sum
my_choices['count']=0
my_choices['oop_family_sum']=0
my_choices['oop_family_sum_adj']=0
for index, person in enumerate(people):
loc_exp_change=np.where((my_choices[person] == 6)&(my_choices['subsidy_elig_'+str(people_indices[index])]==1))[0]
my_choices.loc[loc_exp_change, 'exp' + str(people_indices[index])] =my_choices.loc[loc_exp_change, 'exp' + str(people_indices[index])]+ my_choices.loc[loc_exp_change, 'exp' + str(people_indices[index])] \
* ((my_choices.loc[loc_exp_change, 'cost_sharing_' + str(people_indices[index])]-self.silver_av) / self.silver_av)*self.elasticity
if people_indices[index]<4:
my_choices['count']=my_choices['count']+((my_choices[person]==6).astype(int))*((my_choices['subsidy_elig_'+str(people_indices[index])]==1).astype(int))
my_choices['oop_family_sum']=my_choices['oop_family_sum']+((my_choices[person]==6).astype(int))*((my_choices['subsidy_elig_'+str(people_indices[index])]==1).astype(int)) \
*(my_choices['oop'+str(people_indices[index])])*((1.0-my_choices['cost_sharing_'+ str(people_indices[index])]).fillna(0))/(1-self.silver_av)
my_choices['oop_family_sum_adj'] = my_choices['oop_family_sum_adj'] + ((my_choices[person] == 6).astype(int)) * ((my_choices['subsidy_elig_' + str(people_indices[index])] == 1).astype(int)) \
* (my_choices['oop' + str(people_indices[index])+'_adj']) * ((1.0 - my_choices['cost_sharing_' + str(people_indices[index])]).fillna(0)) / (1 - self.silver_av)
else:
my_choices['count'] = my_choices['count'] + ((my_choices[person] == 6).astype(int)) * ((my_choices['subsidy_elig_' + str(people_indices[index])] == 1).astype(int)) \
*((my_choices['tax_dependent_' + str(people_indices[index])] ==1).astype(int))
my_choices['oop_family_sum']=my_choices['oop_family_sum'] + ((my_choices[person] == 6).astype(int)) * ((my_choices['subsidy_elig_' + str(people_indices[index])] == 1).astype(int)) \
*((my_choices['tax_dependent_' + str(people_indices[index])] ==1).astype(int))*(my_choices['oop' + str(people_indices[index])]) \
* ((1 - my_choices['cost_sharing_' + str(people_indices[index])]).fillna(0)) / (1 - self.silver_av)
my_choices['oop_family_sum_adj'] = my_choices['oop_family_sum_adj'] + ((my_choices[person] == 6).astype(int)) * ((my_choices['subsidy_elig_' + str(people_indices[index])] == 1).astype(int)) \
* ((my_choices['tax_dependent_' + str( people_indices[index])] == 1).astype(int)) * (my_choices['oop' + str(people_indices[index])+'_adj']) \
* ((1 - my_choices['cost_sharing_' + str(people_indices[index])]).fillna(0)) / (1 - self.silver_av)
my_choices['oop_family_number']=0
my_choices['oop_family_number_adj'] = 0
my_choices.loc[my_choices['count']>1,'oop_family_number']=np.minimum( (my_choices.loc[my_choices['count']>1,'oop_family_sum']), (my_choices.loc[my_choices['count']>1,'oop_family_max_0'])) \
/ my_choices.loc[my_choices['count']>1,'count']
my_choices.loc[my_choices['count'] > 1, 'oop_family_number_adj'] = np.minimum((my_choices.loc[my_choices['count'] > 1, 'oop_family_sum_adj']),(my_choices.loc[my_choices['count'] > 1, 'oop_family_max_0'])) \
/ my_choices.loc[ my_choices['count'] > 1, 'count']
#update oop value
for index, person in enumerate(people):
#no need to consider tiac, count=1 means you must in oop_single,count>1 means you are in family
if people_indices[index] < 4:
loc_oop_single=np.where((my_choices['count']==1)&(my_choices[person] == 6)&(my_choices['subsidy_elig_'+str(people_indices[index])]==1))[0]
loc_oop_family=np.where((my_choices['count']>1)&(my_choices[person] == 6)&(my_choices['subsidy_elig_'+str(people_indices[index])]==1))[0]
my_choices.loc[loc_oop_single,'oop'+str(people_indices[index])]=np.minimum(my_choices.loc[loc_oop_single,'oop_family_sum'],my_choices.loc[loc_oop_single,'oop_single_max_'+str(people_indices[index])])
my_choices.loc[loc_oop_single, 'oop' + str(people_indices[index])+'_adj'] = np.minimum(my_choices.loc[loc_oop_single, 'oop_family_sum_adj'],my_choices.loc[loc_oop_single, 'oop_single_max_' + str(people_indices[index])])
my_choices.loc[loc_oop_family, 'oop' + str(people_indices[index])]=my_choices.loc[loc_oop_family,'oop_family_number']
my_choices.loc[loc_oop_family, 'oop' + str(people_indices[index])+'_adj'] = my_choices.loc[loc_oop_family, 'oop_family_number_adj']
# consider tiac situation, recalculate oop value for tiac silver
else:
loc_oop_single = np.where((my_choices['count'] == 1) & (my_choices[person] == 6) & (my_choices['subsidy_elig_' + str(people_indices[index])] == 1)&(my_choices['tax_dependent_' + str(people_indices[index])] == 1))[0]
loc_oop_family = np.where((my_choices['count'] > 1) & (my_choices[person] == 6) & (my_choices['subsidy_elig_' + str(people_indices[index])] == 1&(my_choices['tax_dependent_' + str(people_indices[index])] == 1)))[0]
my_choices.loc[loc_oop_single, 'oop' + str(people_indices[index])] = np.minimum(my_choices.loc[loc_oop_single, 'oop_family_sum'],my_choices.loc[loc_oop_single, 'oop_single_max_' + str(people_indices[index])])
my_choices.loc[loc_oop_single, 'oop' + str(people_indices[index]) + '_adj'] = np.minimum(my_choices.loc[loc_oop_single, 'oop_family_sum_adj'],my_choices.loc[loc_oop_single, 'oop_single_max_' + str(people_indices[index])])
my_choices.loc[loc_oop_family, 'oop' + str(people_indices[index])] = my_choices.loc[loc_oop_family, 'oop_family_number']
my_choices.loc[loc_oop_family, 'oop' + str(people_indices[index])+ '_adj'] = my_choices.loc[loc_oop_family, 'oop_family_number_adj']
loc_ind_adult_child=np.where( (my_choices[person] == 6) & (my_choices['subsidy_elig_' + str(people_indices[index])] == 1&(my_choices['tax_dependent_' + str(people_indices[index])] == 0)))[0]
temp=my_choices.loc[loc_ind_adult_child, 'oop' + str(people_indices[index])]*((1-my_choices.loc[loc_ind_adult_child,'cost_sharing_'+str(people_indices[index])]).fillna(0))/(1 - self.silver_av)
temp_adj=my_choices.loc[loc_ind_adult_child, 'oop' + str(people_indices[index])+'_adj']*((1-my_choices.loc[loc_ind_adult_child,'cost_sharing_'+str(people_indices[index])]).fillna(0))/(1 - self.silver_av)
my_choices.loc[loc_ind_adult_child, 'oop' + str(people_indices[index])]=np.minimum(temp,my_choices.loc[loc_ind_adult_child,'oop_single_max_'+str(people_indices[index])])
my_choices.loc[loc_ind_adult_child, 'oop' + str(people_indices[index])+'_adj'] = np.minimum(temp_adj, my_choices.loc[loc_ind_adult_child, 'oop_single_max_' + str(people_indices[index])])
cols_to_drop = cost_sharing_columns + oop_single_columns + oop_family_columns+['count','oop_family_sum','oop_family_number','oop_family_sum_adj','oop_family_number_adj']
my_choices.drop(cols_to_drop, axis=1, inplace = True)
return my_choices