Source code for src.HieuTable

 #!/usr/bin/env python
import random
import os
import re
import pdb

import pandas as pd
import numpy as np
from scipy import stats

from src.WorkerTable import Worker as Worker
from policy_modules.exchange import Exchange as Exchange
from policy_modules.cost_sharing_subsidy import CostSharing as CostSharing
from policy_modules.uninsured_penalty import UninsuredPenalty as UninsuredPenalty
from policy_modules.mcaid_elig import McaidEligibility as McaidEligibility
from policy_modules.fpl import Fpl as Fpl
from policy_modules.fam_tax import FedTax as FedTax
from utility_modules.math_functions import expand_grid
from utility_modules.multi_merge import multi_merge
from utility_modules.function_dict import populate_fun_dict
from utility_modules.function_dict import plan_ids

[docs]class Hieu(): def __init__(self, hieu_table, ind_parms = None): """ __init__: initializes member variables remove irrelevant persons and index using hieu_id, person_id """ # hieu_table = hieu_table.loc[hieu_table['person_id'].notnull()] # hieu_table.set_index(['hieu_id', 'person_type'], inplace=True) self.__hieu_table = hieu_table self.__pop_hieu = hieu_table #initializing individual behavior related parameters """ Getters """
[docs] def get_hieu_table(self): return self.__hieu_table.copy()
[docs] def get_choices(self): return self.__choices.copy()
[docs] def get_pop_hieu(self): return self.__pop_hieu.copy()
[docs] def get_long_calib_table(self): return self.__long_calib_table.copy()
""" Mutators """
[docs] def set_hieu_table(self, new_data): self.__hieu_table = new_data
[docs] def set_choices(self, new_data): self.__choices = new_data
[docs] def set_pop_hieu(self, new_data): #assert new_data.columns.shape[0] == 55, "the populated hieu does not have 55 columns" self.__pop_hieu = new_data
[docs] def set_long_calib_table(self, new_data): self.__long_calib_table = new_data
[docs] def make_pop_df(self, firm, Curr_esi, family_table, worker_table): """ Input: 1. firm id 2. current esi 3. family table Output: 1. worker table 2. pop_df: a small version of hieu_table with family income and family_size choice_types = ['adult_1', 'adult_2', 'child_1', 'child_2', \ 'adult_child_1', 'adult_child_2', 'adult_child_3', 'adult_child_4'] """ #subset worker_table to just workers who have current firm_id #if (firm == 5000686): wrk_df = worker_table[worker_table['firm_id'] == firm] #subset hieu_table to just rows with hieu_id in wrk_df's hieu_id hieu_df = self.get_hieu_table() pop_df0 = self.get_pop_hieu() pop_df = hieu_df.loc[hieu_df.hieu_id.isin(wrk_df.hieu_id)] # subsetting pop_df = pd.merge(pop_df, pop_df0[['hieu_id', 'person_type', 'mcaid_elig_exante', 'predicted_exante_elig', \ 'new_mcaid_elig', 'mcaid_elig']], on=['hieu_id', 'person_type'], how='left') pop_df = pd.merge(pop_df, family_table[['family_id','fam_income', 'family_size', 'tax_filing_status']], on="family_id", how= "left") pop_df_columns = pop_df.columns.values fake_hieu_shape = pd.DataFrame(data=np.nan,index=range(0, 8), columns=pop_df_columns) fake_hieu_shape.hieu_id = 4000000 for x in range(0, 8): fake_hieu_shape.loc[[x], 'person_type'] = x fake_hieu_shape.family_id=0 pop_df = pd.concat([pop_df, fake_hieu_shape], axis=0, ignore_index=True) pop_df.family_id.astype('int64') #pop_df.person_id.astype('int64') pop_df.drop_duplicates(subset=['hieu_id', 'person_type'], keep=False, inplace=True) ##determine part time full time status wrk_df['part_time'] = 0 wrk_df.loc[wrk_df.hrs_week<30, 'part_time'] = 1 return (pop_df, wrk_df)
[docs] def income_adjuster(self, premium, income, income_adjuster): # return perceived premium for each combined choice at hieu level if (income <= 100): return 1 else: return min(income_adjuster[1], max(income_adjuster[2], ((premium/income)/income_adjuster[3])**income_adjuster[4]))
[docs] def individual_behavior(self, Curr_esi, Esi_0, xc_prem, individual_mandate, family_table, worker_table, firm_table, income_adjuster): # initialize borg objects self.Exchange = Exchange() self.CostSharing = CostSharing() self.UninsuredPenalty = UninsuredPenalty() self.Mcaid = McaidEligibility() self.Fpl = Fpl() self.FedTax = FedTax() """ items need to be accounted for 1. mcaid eligibility 2. mcaid premium 3. exchange subsidy eligibility 4. exchange premiumfamily_table 5. updated out-of-pocket based on cost-sharing 6. esi premium 7. proxy premium 8. individual penalty amount 9. calibration parameters """ # pop_df contains updated family income by merging with self.Family (line 156) (pop_df, wrk_df) = self.make_pop_df(firm_table.curr_firm, Curr_esi, family_table, worker_table) #expand choices by esi plans temp_firm = firm_table[['firm_id', 'curr_choice']] temp_firm.is_copy = False # fam_income exists from this point on... expnd_choices = self.esi_expand(self.get_choices(), worker_table, pop_df, temp_firm, Curr_esi) #pop_df['n_person'] = pop_df['n_person'].fillna(0) n_person = pop_df.pivot('hieu_id', 'person_type', 'n_person') #n_person.fillna(0, inplace=True) n_person = n_person.fillna(0.0).astype(int) n_person.columns = ['n_person_' + str(i) for i in range(8)] n_person = n_person.reset_index() #n_person.fillna(0, inplace=True) expnd_choices = pd.merge(expnd_choices, n_person[['hieu_id','n_person_2', 'n_person_3']], on='hieu_id', how='left') people = ['adult_1','adult_2','child_1','child_2','adult_child_1','adult_child_2','adult_child_3','adult_child_4'] esi_fac = float(self.utility_parms[0]) xc_fac = pd.Series(data=[float(self.utility_parms[1]), float(self.utility_parms[2])]) # xc_fac[0] to be used for xc_sub = 0, and xc_fac[1] for xc_sub = 1 mc_fac = float(self.utility_parms[3]) cal_fac = float(self.utility_parms[4]) pen_fac = float(self.utility_parms[5]) ### compute all necessary variables for long data # 1. mcaid eligibility pop_df['fpl'] = self.Fpl.calculate_fpl(pop_df) pop_df = self.Mcaid.determine_elig(pop_df) # including both rigorous medicaid eligibility and predicted eligibili if self.use_pred_mcaid == True: pop_df['mcaid_all'] = pop_df['mcaid_elig'] | pop_df['predicted_elig'] | pop_df['predicted_exante_elig'] else: pop_df['mcaid_all'] = pop_df['mcaid_elig'] | pop_df['predicted_exante_elig'] # 2. mc_premium pop_df_xc_elig = self.Exchange.subsidy_elig(pop_df, worker_table, Curr_esi, self.affordability_type) pop_df['mc_premium']= self.Mcaid.calculate_premium(pop_df_xc_elig, self.mcaid_shadow_premium) # 3. subsidy elig pop_df['subsidy_elig'] = pop_df_xc_elig['subsidy_elig'] pop_df['adultkid_subsidy_elig']= pop_df_xc_elig['adultkid_subsidy_elig'] # compute columns to flatten multi-index mcaid_cols = ['mcaid_%d' % i for i in range(8)] new_columns = ['adultkid_xc_sub_'+ str(i) for i in range(8)]+['mcaid_prem_' + str(i) for i in range(8)]+mcaid_cols + ['new_' + col for col in mcaid_cols] + ['pred_' + col for col in mcaid_cols] + ['xc_sub_'+ str(i) for i in range(8)] # pivot once to turn wide data (with new variables) to long new_variables = pd.pivot_table(pop_df, index='hieu_id', columns='person_type', values=['adultkid_subsidy_elig','mc_premium','mcaid_all', 'new_mcaid_elig', 'predicted_elig', 'subsidy_elig']) new_variables.mcaid_all=new_variables.mcaid_all.fillna(False).astype(bool) new_variables = new_variables.fillna(0.0).astype(int) new_variables.mcaid_all= new_variables.mcaid_all.astype(bool) # flatten multi-index new_variables.columns = new_columns expnd_choices = pd.merge(expnd_choices, new_variables, left_on='hieu_id', right_index=True, how='left') # i. if they are subsidy eligible, delete their medicaid choice # ii. if any row has a choice type = 9 and a respective mcaid_ = 0, then cut that row; this could happen due to wage change if (self.dual == 0): for i, person in enumerate(people): expnd_choices.drop(expnd_choices.loc[(expnd_choices['xc_sub_' + str(i)] == 1) & (expnd_choices[person] == 9)].index.values, inplace=True) expnd_choices.drop(expnd_choices.loc[(expnd_choices[person] == 9) & (expnd_choices[mcaid_cols[i]] == 0)].index.values, inplace=True) else: for i, person in enumerate(people): expnd_choices['dual_' + str(i)] = (expnd_choices['xc_sub_'+str(i)] == 1) & (expnd_choices['mcaid_'+str(i)] == 1) expnd_choices.drop(expnd_choices.loc[(expnd_choices[person] == 9) & (expnd_choices[mcaid_cols[i]] == 0)].index.values, inplace=True) # only those with medicaid choice should have premium for index, person in enumerate(people): expnd_choices['mcaid_prem_' + str(index)] = expnd_choices['mcaid_prem_' + str(index)] * (expnd_choices[person]==9) # 4. populate exchange premiums, returns columns: [person + '_xc_prem'] try: curr_av_value = Curr_esi[Curr_esi['firm_id']==firm_table.curr_firm]['av_value'].iloc[0] except: curr_av_value = 0.7 expnd_choices = self.Exchange.xc_premium_amount(pop_df_xc_elig, worker_table, xc_prem, Curr_esi, expnd_choices, self.affordability_type, curr_av_value) # 5. exchange cost sharing and exchange oop update expnd_choices = self.CostSharing.oop_update(expnd_choices, pop_df_xc_elig) oop_cols = ['oop' + str(i) for i in range(8)] # 6 and 7. esi premiums, as well as proxy premiums expnd_choices = self.esi_premium(expnd_choices, Curr_esi, Esi_0, family_table, firm_table, worker_table) esi_prem_cols = ['esi_premium_' + str(i) for i in range(8)] wage_cols = ['wage_delta_' + str(i) for i in range(8)] for index, person in enumerate(people): expnd_choices['esi_prem_wage_' + str(index)] = expnd_choices['esi_premium_' + str(index)] + expnd_choices['wage_delta_' + str(index)] expnd_choices['esi_contr'] = expnd_choices[esi_prem_cols].sum(axis=1) # 8. applying bronze tier ratio to calibration parameters bronze_7_1 = self.bronze_ratio[0]*2 # with subsidy bronze_7_0 = self.bronze_ratio[1]*2 # without subsidy for i, person in enumerate(people): expnd_choices['cal' + str(i)][(expnd_choices[person]==7) & (expnd_choices['subsidy_elig_' + str(i)] ==1) ] = \ expnd_choices['cal' + str(i)][(expnd_choices[person]==7) & (expnd_choices['subsidy_elig_' + str(i)] ==1) ]*bronze_7_1 expnd_choices['cal' + str(i)][(expnd_choices[person]==7) & (expnd_choices['subsidy_elig_' + str(i)] ==0 )] = \ expnd_choices['cal' + str(i)][(expnd_choices[person]==7) & (expnd_choices['subsidy_elig_' + str(i)] ==0 )]*bronze_7_0 ## 9. calibration amount new_cali_cols = ['new_cal'+ str(i) for i in range(8)] # new calibration parameters cali_cols = ['cal'+ str(i) for i in range(8)] if set(new_cali_cols).issubset(expnd_choices.columns) and self.use_cal_flag == 1: for i in range(8): expnd_choices['cal'+str(i)] = expnd_choices['cal'+str(i)] + expnd_choices['new_cal'+str(i)] # 10. incorporate penalty expnd_choices['total_premiums'] = expnd_choices['esi_contr'] + expnd_choices['exchange_prem'] pop_df = self.UninsuredPenalty.cheapest_coverage(expnd_choices, pop_df_xc_elig) expnd_choices = self.UninsuredPenalty.penalty(pop_df, expnd_choices, individual_mandate, self.flat_penalties, pen_fac) expnd_choices[['penalty_' + str(i) for i in range(8)]] = expnd_choices[['penalty_' + str(i) for i in range(8)]].fillna(0) expnd_choices[['penalty_orig_' + str(i) for i in range(8)]] = expnd_choices[['penalty_orig_' + str(i) for i in range(8)]].fillna(0) # penalty only apply to uninsured choice for i, person in enumerate(people): expnd_choices['penalty_' + str(i)] = (expnd_choices[person]==1)*expnd_choices['penalty_' + str(i)] expnd_choices['penalty_orig_' + str(i)] = (expnd_choices[person] == 1) * expnd_choices['penalty_orig_' + str(i)] # depending which expenditure models to use, to be passed to premium loop if (self.ab_choice == 1 or self.ab_choice ==2): exp_cols = ['exp'+ str(i) for i in range(8)] expnd_choices['total_exp'] = expnd_choices[exp_cols].sum(axis=1) else: exp_cols = ['exp'+ str(i)+'_adj' for i in range(8)] expnd_choices['total_exp'] = expnd_choices[exp_cols].sum(axis=1) oop_cols = ['oop'+ str(i) for i in range(8)] # 11 applying expenditure and oop ratio to expenditures relative to silver and bronze for i, person in enumerate(people): expnd_choices['exp' + str(i)][expnd_choices[person]==6] = expnd_choices['exp' + str(i)][expnd_choices[person]==6]*self.exp_ratio[0]/1.2 expnd_choices['exp' + str(i)][expnd_choices[person]==7] = expnd_choices['exp' + str(i)][expnd_choices[person]==7]*self.exp_ratio[1] expnd_choices['exp' + str(i)][expnd_choices[person]==8] = expnd_choices['exp' + str(i)][expnd_choices[person]==8]*self.exp_ratio[2]/.9 expnd_choices['oop' + str(i)][expnd_choices[person]==6] = expnd_choices['oop' + str(i)][expnd_choices[person]==6]*self.oop_ratio[0]/.75 expnd_choices['oop' + str(i)][expnd_choices[person]==7] = expnd_choices['oop' + str(i)][expnd_choices[person]==7]*self.oop_ratio[1] expnd_choices['oop' + str(i)][expnd_choices[person]==8] = expnd_choices['oop' + str(i)][expnd_choices[person]==8]*self.oop_ratio[2]/1.125 # 12. creating columns for expenditure multiplier, [xc, Oct 10, 2017] for i, person in enumerate(people): expnd_choices['exp_mult' + str(i)] = expnd_choices[[person]].isin([2,3,4,5])*self.exp_multiplier[0] + \ expnd_choices[[person]].isin([6,7])*self.exp_multiplier[1] + \ expnd_choices[[person]].isin([10])*self.exp_multiplier[2] + \ expnd_choices[[person]].isin([9])*self.exp_multiplier[3] + \ expnd_choices[[person]].isin([1])*self.exp_multiplier[4] # set up which set of expenditure model to use if (self.ab_choice ==3 or self.ab_choice ==4): exp_suffix = "_adj" else: exp_suffix = "" if (income_adjuster[0] == 0): for i in range(8): index = str(i) (expnd_choices['exp' + index+exp_suffix]).fillna(value=0, inplace=True) (expnd_choices['cal' + index]*cal_fac).fillna(value=0, inplace=True) (expnd_choices['oop' + index+exp_suffix]).fillna(value=0, inplace=True) (expnd_choices['esi_prem_wage_' + index]).fillna(value=0, inplace=True) (expnd_choices['xc_prem_' + index]).fillna(value=0, inplace=True) (expnd_choices['mcaid_prem_' + index]).fillna(value=0, inplace=True) (expnd_choices['penalty_' + index]).fillna(value=0, inplace=True) (expnd_choices['var' + index]*self.utility_parameter[0]/2).fillna(value=0, inplace=True) expnd_choices['utility_' + index] = expnd_choices['exp' + index+exp_suffix]*self.utility_parameter[1] + \ (expnd_choices['cal' + index]*cal_fac) - \ (expnd_choices['oop' + index+exp_suffix]) - \ (expnd_choices['esi_prem_wage_' + index]*esi_fac) - \ (expnd_choices['xc_prem_' + index]* \ (xc_fac[1]*(expnd_choices['subsidy_elig_' + index]==1).astype(int) + \ xc_fac[0]*(expnd_choices['subsidy_elig_' + index]==0).astype(int))) - \ (expnd_choices['mcaid_prem_' + index]*mc_fac) - \ (expnd_choices['penalty_' + index]) - \ (expnd_choices['var' + index]*self.utility_parameter[0]/2) util_cols = ['utility_'+ str(i) for i in range(8)] expnd_choices['utility'] = expnd_choices[util_cols].sum(axis=1) else: # taking out premium related terms for i in range(8): index = str(i) (expnd_choices['exp' + index+exp_suffix]).fillna(value=0, inplace=True) (expnd_choices['cal' + index]*cal_fac).fillna(value=0, inplace=True) (expnd_choices['oop' + index+exp_suffix]).fillna(value=0, inplace=True) (expnd_choices['wage_delta_' + index]).fillna(value=0, inplace=True) (expnd_choices['penalty_' + index]).fillna(value=0, inplace=True) (expnd_choices['var' + index]*self.utility_parameter[0]/2).fillna(value=0, inplace=True) expnd_choices['utility_p1' + index] = expnd_choices['exp' + index+exp_suffix]*self.utility_parameter[1] + \ (expnd_choices['cal' + index]*cal_fac) - \ (expnd_choices['oop' + index+exp_suffix]) - \ (expnd_choices['wage_delta_' + index]) - \ (expnd_choices['penalty_' + index]) - \ (expnd_choices['var' + index]*self.utility_parameter[0]/2) util_p1_cols = ['utility_p1'+ str(i) for i in range(8)] expnd_choices['utility_p1'] = expnd_choices[util_p1_cols].sum(axis=1) # premium part mcaid_prem_columns = ['mcaid_prem_' + str(i) for i in range(8)] expnd_choices['mcaid_prem'] = expnd_choices[mcaid_prem_columns].sum(axis=1) expnd_choices['total_premiums'] = expnd_choices['total_premiums'] + expnd_choices['mcaid_prem'] expnd_choices['perceived_premium'] = expnd_choices['total_premiums']*expnd_choices.apply(lambda row: \ self.income_adjuster(row['total_premiums'], row['fam_income'], income_adjuster), axis=1) expnd_choices['utility'] = expnd_choices['utility_p1'] - expnd_choices['perceived_premium'] # calculating max utility and making a choice final_choice_df = self.choose_choice(expnd_choices) plan_details = self.plan_details(final_choice_df, firm_table.curr_firm, Curr_esi, people, self.ab_choice) # build long data firm_curr_choice = Curr_esi[['firm_id','choice']] firm_curr_choice.rename(columns={'choice':'curr_choice'}, inplace=True) if self.calib_flag != 0: self.build_long_calib_table(expnd_choices, pop_df_xc_elig, firm_curr_choice, self.calib_flag, self.debug) return (final_choice_df, plan_details)
[docs] def build_long_calib_table(self, expnd_choices, pop_df, firm_df, calib_flag, debug): """ in: expnd_choices - wide data with individual choices or utility parameters calib_flag - 1 is default choice and 2 should be all choices! effect: updates self.long_calib_table with unique utility parameters per unique choice and individual """ # manifest constants (DECLARE LIST OF COLUMNS YOU WANT TO ADD UP HERE, IN SAME FASHION) utility_cols = ['utility_' + str(i) for i in range(8)] exp_cols = ['exp' + str(i) for i in range(8)] oop_cols = ['oop' + str(i) for i in range(8)] esi_prem_wage_cols = ['esi_prem_wage_' + str(i) for i in range(8)] esi_premium_cols = ['esi_premium_'+ str(i) for i in range(8)] esi_wage_cols = ['wage_delta_'+ str(i) for i in range(8)] subsidy_cols = ['subsidy_elig_'+ str(i) for i in range(8)] xc_prem_cols = ['xc_prem_' + str(i) for i in range(8)] age_rated_prem_cols = ['age_rated_premium_' + str(i) for i in range(8)] mcaid_elig_cols = ['mcaid_' + str(i) for i in range(8)] mcaid_prem_cols = ['mcaid_prem_' + str(i) for i in range(8)] penalty_cols = ['penalty_' + str(i) for i in range(8)] var_cols = ['var' + str(i) for i in range(8)] sub_amount_cols = ['sub_amount_'+ str(i) for i in range(8)] people = ['adult_1','adult_2','child_1','child_2','adult_child_1','adult_child_2','adult_child_3','adult_child_4'] person_id = ['p' + str(i) + '_id' for i in range(8)] cali_cols = ['cal' + str(i) for i in range(8)] # new calibration parameters firm_id_cols = ['p0_firm_id','p1_firm_id','p1_firm_id','p2_firm_id','p4_firm_id','p5_firm_id','p6_firm_id','p7_firm_id'] try: long_table_temp = self.get_long_calib_table() except: long_table_temp = pd.DataFrame() # build long data by going though individuals for i in range(8): # initialize base dataframe structure individual_expnd_choices = expnd_choices.drop_duplicates(['hieu_id', people[i]]) # select columns we need (ADD TO HERE IF YOU WANT MORE COLUMNS) individual_expnd_choices = individual_expnd_choices[['hieu_id', 'region', people[i], person_id[i], firm_id_cols[i], \ utility_cols[i], cali_cols[i], exp_cols[i], oop_cols[i], esi_prem_wage_cols[i], \ esi_premium_cols[i], esi_wage_cols[i], subsidy_cols[i], sub_amount_cols[i], age_rated_prem_cols[i], \ xc_prem_cols[i], mcaid_prem_cols[i], mcaid_elig_cols[i], penalty_cols[i], var_cols[i]]] # rename the appropriate columns (IF YOU ADD, MAKE SURE YOU RENAME) # this is all at individual level, not aggregated to hieu level individual_expnd_choices.rename( index=str, columns={ people[i]: 'choice', \ utility_cols[i]: 'utility', \ firm_id_cols[i]: 'firm_id', \ cali_cols[i]: 'calib', \ person_id[i]: 'person_id', \ exp_cols[i]: 'exp', \ oop_cols[i]: 'oop', \ esi_prem_wage_cols[i]: 'esi_prem_wage_change', \ esi_premium_cols[i]: 'esi_prem', \ esi_wage_cols[i]: 'esi_wage', \ subsidy_cols[i]: 'subsidy_elig', \ age_rated_prem_cols[i]: 'age_rated_premium', \ sub_amount_cols[i]: 'sub_amount', \ xc_prem_cols[i]: 'xc_prem', \ mcaid_prem_cols[i]: 'mcaid_prem', \ mcaid_elig_cols[i]: 'mcaid_elig', \ penalty_cols[i]: 'penalty', \ var_cols[i]: 'var_oop' }, inplace=True ) # remove invalid individual_expnd_choices = individual_expnd_choices[individual_expnd_choices['choice'] != 0] individual_expnd_choices['person_type'] = people[i] # merging hieu_df to get more variables hieu_temp = pop_df[['person_id', 'p_weight', 'policy_holder', 'fpl', 'doc_status','affordability','fam_income', 'family_size', 'family_cap', 'age','coverage']] individual_expnd_choices = pd.merge(individual_expnd_choices, hieu_temp, on = 'person_id', how = 'left') individual_expnd_choices = pd.merge(individual_expnd_choices, firm_df, on = 'firm_id', how = 'left') if (long_table_temp.empty == False): temp_df = long_table_temp[~np.in1d(long_table_temp.person_id, individual_expnd_choices.person_id)] temp_df = temp_df.reindex() long_table = pd.concat([temp_df, individual_expnd_choices]) long_table_temp = long_table long_table.dropna(subset=['person_id'], inplace=True) else: long_table_temp = individual_expnd_choices self.set_long_calib_table(long_table)
### fixing it, so it returns the right values to the right cells, [xc 1/2/2017]
[docs] def esi_premium(self, choices, esi, esi0, family_table, firm_table, worker_table): func_dict = populate_fun_dict() cols = ['ins_p0', 'ins_p1', 'ins_p4', 'ins_p5', 'ins_p6', 'ins_p7'] for i in range(8): choices['esi_premium_'+ str(i)] = 0 choices['wage_delta_'+ str(i)] = 0 nrows = choices.shape[0] esi_contribution = np.zeros((nrows, 6)) wage_change = np.zeros((nrows, 6)) mykeys = pd.unique(choices[cols].values.ravel()) mykeys = mykeys[np.isfinite(mykeys)] for ins in mykeys: if int(ins) != 0: loc = np.where(choices[cols] == ins) temp = plan_ids(choices, loc) if (np.all(np.isnan(temp)) ==False): x = func_dict[ins](choices, loc, esi, esi0, self.get_hieu_table(), family_table, firm_table, self.FedTax) # populating the esi_contribution, a for loop right now [xc]s for index in range(x[0].shape[0]): esi_contribution[loc[0][index], loc[1][index]] = x[0][index] wage_change[loc[0][index], loc[1][index]] = x[1][index] person_types = [0,1,4,5,6,7] for index, p_type in enumerate(person_types): choices['esi_premium_%d' % p_type] = esi_contribution[:, index] choices['wage_delta_%d' % p_type] = wage_change[:, index] #change wage_delta to 0 if it makes that person go below minimum_wage for i in person_types: choices=pd.merge(choices,worker_table[['person_id','wages','minimum_wage']],how='left',left_on=('p%d_id' %i) ,right_on='person_id') choices['new_wage']= choices.wages-choices['wage_delta_%d' %i] choices[choices['new_wage']<choices['minimum_wage']]['wage_delta_%d' %i]=0 choices.drop(['person_id','wages','new_wage','minimum_wage'],axis=1,inplace=True) return choices
[docs] def set_utility(self, ind_parms): if ind_parms !=None: self.utility_parms = ind_parms['utility_params'] self.exp_multiplier = ind_parms['exp_multiplier'] self.flat_penalties = ind_parms['flat_penalties'] self.dual= ind_parms['dual'] self.debug= ind_parms['debug'] self.mcaid_shadow_premium= ind_parms['mcaid_shadow_premium'] self.use_cal_flag= ind_parms['use_cal_flag'] self.ab_choice= ind_parms['ab_choice'] self.calib_flag= ind_parms['calib_flag'] self.cal_multipliers= ind_parms['cal_multipliers'] self.utility_parameter= ind_parms['utility_parameter'] self.long_debug_run= ind_parms['long_debug_run'] self.bronze_ratio = ind_parms['bronze_ratio'] self.exp_ratio = ind_parms['exp_xc_multiplier'] self.oop_ratio = ind_parms['oop_xc_multiplier'] self.affordability_type=ind_parms['affordability_type'] self.use_pred_mcaid = ind_parms['use_pred_mcaid']
[docs] @classmethod def esi_expand(cls, choice_hieu, wrk_df, pop_df, temp_firm, Curr_esi): """ choice_types are choice_types = ['adult_1', 'adult_2', 'child_1', 'child_2','adult_child_1', 'adult_child_2','adult_child_3', 'adult_child_4'] corresponding to indices 0 1 2 3 4 5 6 7 Curr_esi.columns.values=['index' 'av_value' 'ch' 'choice' 'contr_p_ch' 'contr_p_fam' 'contr_p_self' 'contr_p_sp' 'firm_id' 'oop_ch' 'oop_ch_actual' 'oop_fam' 'oop_fam_actual' 'oop_self' 'oop_self_actual' 'oop_sp' 'oop_sp_actual' 'plan_id' 'premium_ch' 'premium_ch_actual' 'premium_fam' 'premium_fam_actual' 'premium_self' 'premium_self_actual' 'premium_sp' 'premium_sp_actual' 'pt' 'sp'] the goal is to link plan_id with each policy holder, when the person is eligible for the plan """ # need to index the data by hieu_id and choice_types columns [xc] choice_hieu = choice_hieu.reset_index(drop=True) hieu_idx = choice_hieu['hieu_id'].unique() #merge in choice type to wrk_df wrk_df = pd.merge(wrk_df, temp_firm, on= "firm_id", how = 'left') wrk_df['person_id']=wrk_df['person_id'].astype(float) # steps needed here to see who is eligible for the plan offered [xc] choice_hieu = pd.merge(choice_hieu, Curr_esi[['firm_id', 'plan_id', 'pt']], left_on='p0_firm_id', right_on='firm_id', how='left') choice_hieu.rename( columns={'plan_id': 'p0_plan_id', 'firm_id_x': 'p0_firm_id', 'pt':'pt_0'}, inplace=True) choice_hieu.drop('firm_id', axis=1, inplace=True) indices = [1,4,5,6,7] for i in indices: choice_hieu = pd.merge(choice_hieu, Curr_esi[['firm_id', 'plan_id','pt']], left_on='p%d_firm_id' % i, right_on='firm_id', how='left') choice_hieu.rename( columns={'plan_id': 'p%d_plan_id' % i, 'firm_id_x': 'p%d_firm_id' % i, 'pt':'pt_%d' % i}, inplace=True) choice_hieu.drop('firm_id', axis=1, inplace=True) pid = ['p0_id', 'p1_id', 'p2_id', 'p3_id', 'p4_id', 'p5_id', 'p6_id', 'p7_id'] mod_wrk_df = wrk_df[['person_id','full_time']].copy() #add esielig and full_time to choice_hieu table for i in pid: mod_wrk_df.columns.values[1] = 'full_time_' + str(i)[1] choice_hieu = pd.merge(choice_hieu, mod_wrk_df, left_on=i, right_on = 'person_id', how = 'left') del choice_hieu['person_id_x'] del choice_hieu['person_id_y'] #add in_firm_weight to choice_hieu table mod_wrk_df = wrk_df[['person_id','in_firm_weight']].copy() for i in pid: mod_wrk_df.columns.values[1] = 'in_firm_weight_' + str(i)[1] choice_hieu = pd.merge(choice_hieu, mod_wrk_df, left_on=i, right_on = 'person_id', how = 'left') choice_hieu['in_firm_weight_' + str(i)[1]] = choice_hieu['in_firm_weight_'+ str(i)[1]].fillna(0) del choice_hieu['person_id_x'] del choice_hieu['person_id_y'] mod_wrk_df = wrk_df[['person_id', 'esi_not_elig']].copy() for i in pid: mod_wrk_df.columns.values[1] = 'esi_not_elig_' + str(i)[1] choice_hieu = pd.merge(choice_hieu, mod_wrk_df, left_on=i, right_on='person_id', how='left') choice_hieu['esi_not_elig_' + str(i)[1]] = choice_hieu['esi_not_elig_' + str(i)[1]].fillna(0) del choice_hieu['person_id_x'] del choice_hieu['person_id_y'] mod_pop_df=pop_df[['person_id','tax_dependent']].copy() mod_pop_df.dropna(subset=['person_id'], inplace=True) for i in pid: mod_pop_df.columns.values[1] = 'tax_dependent_' + str(i)[1] choice_hieu = choice_hieu.merge(mod_pop_df, left_on=i, right_on='person_id', how='left') choice_hieu['tax_dependent_' + str(i)[1]] = choice_hieu['tax_dependent_' + str(i)[1]].fillna(2) choice_hieu.drop(['person_id'],inplace=True,axis=1) mod_pop_df = pop_df[['person_id', 'ind_income']].copy() mod_pop_df.dropna(subset=['person_id'], inplace=True) for i in pid: mod_pop_df.columns.values[1] = 'ind_income_' + str(i)[1] choice_hieu = pd.merge(choice_hieu, mod_pop_df, left_on=i, right_on='person_id', how='left') choice_hieu['ind_income_' + str(i)[1]] = choice_hieu['ind_income_' + str(i)[1]].fillna(0) choice_hieu.drop(['person_id'], inplace=True, axis=1) #cut rows where esielig_ = 0 #for i in esi_elig: # choice_hieu = choice_hieu.drop(choice_hieu.index[np.where(choice_hieu[i]==0)[0]]) indices = [0,1,4,5,6,7] people = ['adult_1','adult_2','child_1','child_2','adult_child_1','adult_child_2','adult_child_3','adult_child_4'] #cut rows where a person is working part time but their plan doesn't cover part time workers for i in indices: choice_hieu = choice_hieu.drop(choice_hieu.index[np.where((choice_hieu['full_time_%d' % i]==0) & (choice_hieu['pt_%d' % i]==0) & (choice_hieu[people[i]]==2))[0]]) # drop worker whose working hour is lower than threshold choice_hieu = choice_hieu.drop(choice_hieu.index[np.where((choice_hieu['esi_not_elig_%d' % i] == 1) & (choice_hieu[people[i]] == 2))[0]]) # trimming choice_hieu = choice_hieu[ ~((choice_hieu[people[i]] ==2) & (choice_hieu['p%d_plan_id' % i].isnull()))] choice_hieu['p2_plan_id'] = (choice_hieu.child_1 == 4)*choice_hieu.p0_plan_id.fillna(0) + (choice_hieu.child_1 == 5)*choice_hieu.p1_plan_id.fillna(0) choice_hieu['p3_plan_id'] = (choice_hieu.child_2 == 4)*choice_hieu.p0_plan_id.fillna(0) + (choice_hieu.child_2 == 5)*choice_hieu.p1_plan_id.fillna(0) choice_hieu['p2_firm_id'] = (choice_hieu.child_1 == 4)*choice_hieu.p0_firm_id + (choice_hieu.child_1 == 5)*choice_hieu.p1_firm_id choice_hieu['p3_firm_id'] = (choice_hieu.child_2 == 4)*choice_hieu.p0_firm_id + (choice_hieu.child_2 == 5)*choice_hieu.p1_firm_id #choice_hieu.reset_index(inplace=True) choice_hieu['hieu_idx'] = pd.merge(choice_hieu[['hieu_id']], pop_df['hieu_id'].drop_duplicates().reset_index(), how = 'left')['index'] choice_hieu = pd.merge(choice_hieu, pop_df[['hieu_id','fam_income']].drop_duplicates().reset_index(), how = 'left', on ='hieu_id') return (choice_hieu)
[docs] @staticmethod def choose_choice(x): # pick a row with maximum utility for each hieu, and choose the first one if duplicates occur [xc] idx = x.groupby(['hieu_id'])['utility'].transform(max) == x['utility'] y = x[idx] y = y.groupby('hieu_id').first() final_choice_df = y.reset_index() final_choice_df['x_index'] = final_choice_df.index return (final_choice_df)
[docs] @staticmethod def plan_details(final_choice_df, firm, Curr_esi, choice_types, ab_choice): """ input: choice_table after utility current firm of interest return: 1. number of people by plan_id and by plan_type (self, sp, ch and fam) 2. number of policy holders by plan_id and by plan_type (self, sp, ch and fam) 3. total expenditure by plan_id and by plan_type (self, sp, ch and fam) 4. AV value of the plans """ fchoice = Curr_esi[['firm_id', 'plan_id']][Curr_esi.firm_id == firm] chosen_plans = fchoice['plan_id'].values.tolist() # allows more than one plan # outtable has the same number of rows as the number of plan_ids outtable = fchoice outtable.reset_index(drop=True, inplace=True) # step 1: identifying plan_id(s) of the focal firm pcols = ['p%d_plan_id' % i for i in range(8)] choice_i = final_choice_df[choice_types] policy_type_col = final_choice_df[['ins_p0', 'ins_p1','ins_p4','ins_p5','ins_p6','ins_p7']] # use un-adjusted expenditure in premium loop or adjusted depending on the option if ab_choice ==1: exp_cols = final_choice_df[['exp0', 'exp1', 'exp2', 'exp3', 'exp4', 'exp5', 'exp6', 'exp7']] oop_cols = final_choice_df[['oop0', 'oop1', 'oop2', 'oop3', 'oop4', 'oop5', 'oop6', 'oop7']] else: exp_cols = final_choice_df[['exp0_adj', 'exp1_adj', 'exp2_adj', 'exp3_adj', 'exp4_adj', 'exp5_adj', 'exp6_adj', 'exp7_adj']] oop_cols = final_choice_df[['oop0_adj', 'oop1_adj', 'oop2_adj', 'oop3_adj', 'oop4_adj', 'oop5_adj', 'oop6_adj', 'oop7_adj']] adk_choice = choice_i.values[:, [4,5,6,7]] wgt_cols = ['in_firm_weight_' + str(i) for i in range(8)] weights = final_choice_df[wgt_cols].values # step 2: number of policy holders and type of policy holders for index, plan in enumerate(chosen_plans): temp = final_choice_df[pcols].isin([plan]).values adk_sp_plns = reduce(np.multiply,[temp[:,[4,5,6,7]], weights[:,[4,5,6,7]], (adk_choice==2)]).sum() ad1 = final_choice_df[['p0_plan_id']].isin([plan]).values ad_1_s_plns = ad1*final_choice_df[['in_firm_weight_0']].values*final_choice_df[['ins_p0']].isin([1,5,9]).values ad_1_sp_plns = ad1*final_choice_df[['in_firm_weight_0']].values*final_choice_df[['ins_p0']].isin([2,6,10]).values ad_1_ch_plns = ad1*final_choice_df[['in_firm_weight_0']].values*final_choice_df[['ins_p0']].isin([3,7,11]).values ad_1_fam_plns = ad1*final_choice_df[['in_firm_weight_0']].values*final_choice_df[['ins_p0']].isin([4,8,12]).values ad2 = final_choice_df[['p1_plan_id']].isin([plan]).values ad_2_s_plns = ad2*final_choice_df[['in_firm_weight_1']].values*final_choice_df[['ins_p1']].isin([1,5,9]).values ad_2_sp_plns = ad2*final_choice_df[['in_firm_weight_1']].values*final_choice_df[['ins_p1']].isin([2,6,10]).values ad_2_ch_plns = ad2*final_choice_df[['in_firm_weight_1']].values*final_choice_df[['ins_p1']].isin([3,7,11]).values ad_2_fam_plns = ad2*final_choice_df[['in_firm_weight_1']].values*final_choice_df[['ins_p1']].isin([4,8,12]).values outtable.loc[index, 's_holder'] = adk_sp_plns.sum() + ad_1_s_plns.sum() + ad_2_s_plns.sum() outtable.loc[index, 'sp_holder'] = ad_1_sp_plns.sum() + ad_2_sp_plns.sum() outtable.loc[index, 'ch_holder'] = ad_1_ch_plns.sum() + ad_2_ch_plns.sum() outtable.loc[index, 'fam_holder'] = ad_1_fam_plns.sum() + ad_2_fam_plns.sum() on_plans = reduce(np.multiply, [temp, choice_i.isin([2,3,4,5])]) exp_plans = reduce(np.multiply,[on_plans, weights, exp_cols]) oop_plans = reduce(np.multiply,[on_plans, weights, oop_cols]) outtable.loc[index, 'num_plans'] = on_plans.sum().sum() outtable.loc[index, 'total_exp'] = exp_plans.sum().sum() outtable.loc[index, 'total_oop'] = oop_plans.sum().sum() return outtable