#!/usr/bin/env python
import numpy as np
import pandas as pd
import math
import pdb
from utility_modules.get_parameters import get_params
from policy_modules.fpl import Fpl
from policy_modules.calculate_regression import FplRegression
from utility_modules.exceptions.year_exceptions import YearException as YearException
"""
creating a new column to store medicaid eligibility
related criteria, except fpl, because only fpl depends on iteration.
Everything else is fixed. So this function should be in set-up part.
variables to be merged on: adult, doc, lprle5, having_kids
mcaid_types: pd.DataFrame of mcaid
df: pd.DataFrame of person (0/1) and age
"""
[docs]class McaidEligibility():
# borg singleton config object
__shared_state = {}
def __init__(self, policy_dict = None, sys_params = None):
# implement the borg pattern
self.__dict__ = self.__shared_state
if policy_dict != None:
gid_mcaid = policy_dict['mcaid_elig']
gid_fpl = policy_dict['fpl']
max_year = int(sys_params.max_year)
#read in mcaid data
self.data = get_params(gid_mcaid)
self.wb = self.data[self.data['year']==max_year]
#read in fpl data
self.fpl = get_params(gid_fpl)
self.regression_model= FplRegression(policy_dict)
if (max(self.fpl.year) < max_year):
#make a dataframe for prediction
future = pd.DataFrame(range(max(self.fpl.year)+1, max_year+1))
future.columns = ['year']
#predict new years and return data
future['base'] = self.regression_model.calculate_regression_line(self.fpl.year, self.fpl.base, future[['year']])
future['inc'] = self.regression_model.calculate_regression_line(self.fpl.year, self.fpl.inc, future[['year']])
self.fpl = self.fpl.append(future)
#read in mcaid data
mcaid = get_params(gid_mcaid)
mcaid.index.name = 'type'
mcaid.reset_index(inplace=True)
self.mcaid_types = mcaid[['type','max_age','adult']]
self.mcaid_elig = mcaid[['type','fpl_thresh']]
self.mcaid_threshold = sys_params.medicaid_elig_threshold
[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 in self.fpl.year.values:
self.curr_data = self.fpl[self.fpl.year == curr_year][['base','inc']]
self.curr_data_me = self.data[self.data['year']==curr_year]
else:
raise YearException(str(curr_year)+ " is not a valid year.")
[docs] def pass_threshold(self, threshold, prob):
"""
checks if the probability passed in exceeds the threshold level
specified in the configuration file
"""
return (prob >= threshold).astype(int)
[docs] def produce_elig_exante(self, df):
"""
create column of previously medicaid eligible based on 2013 medicaid eligibility requirements
"""
rules = self.data[self.data['year'] == 2013] # this can be hard-coded, since it doesn't change
mcaid_elig = False
if 'having_kids' in df:
df = df.drop('having_kids', axis=1)
determine_kids = df.loc[(df['person_type'] == 2) | (df['person_type'] == 3)]
determine_kids['having_kids'] = determine_kids['person_id'].notnull()
kid_fams = determine_kids.loc[determine_kids['having_kids'] == True].drop_duplicates('hieu_id')
df = pd.merge(df, kid_fams[['hieu_id','having_kids']], on='hieu_id', how='left')
for index, row in rules.iterrows():
# true medicaid eligibility
if (row['doc'] == 1) & (row['adult'] == 0):
eligTemp = (df['doc_status'] <= 2) & (df['age']>=row['min_age']) & (df['age'] <= row['max_age']) & \
(df['fpl'] <= row['fpl_thresh']) & (df['coverage']!=4)
loc_ind_adult_child = np.where((df['person_type'] > 3) & (df['tax_dependent'] == 0))[0]
eligTemp[loc_ind_adult_child] = (df.loc[loc_ind_adult_child,'doc_status'] <= 2) & (df.loc[loc_ind_adult_child,'age']>=row['min_age']) & (df.loc[loc_ind_adult_child,'age'] <= row['max_age']) & \
(df.loc[loc_ind_adult_child,'ind_fpl'] <= row['fpl_thresh']) & (df.loc[loc_ind_adult_child,'coverage']!=4)
elif (row['doc']==1) & (row['adult'] == 1):
eligTemp = (df['doc_status'] <= 2) & (df['age']>=row['min_age']) & (df['age'] <= row['max_age']) & \
(df['fpl'] <= row['fpl_thresh']) & (df['having_kids'] == 1) & (df['coverage']!=4)
loc_ind_adult_child = np.where((df['person_type'] > 3) & (df['tax_dependent'] == 0))[0]
eligTemp[loc_ind_adult_child] = (df.loc[loc_ind_adult_child, 'doc_status'] <= 2) & (df.loc[loc_ind_adult_child, 'age'] >= row['min_age']) & ( df.loc[loc_ind_adult_child, 'age'] <= row['max_age']) & \
(df.loc[loc_ind_adult_child, 'ind_fpl'] <= row['fpl_thresh']) & (df.loc[loc_ind_adult_child, 'coverage'] != 4) & (df.loc[loc_ind_adult_child,'having_kids'] == 1)
# calculate newly eligible persons
mcaid_elig = mcaid_elig | eligTemp
mcaid_elig =mcaid_elig & (df['coverage'] != 3) & (df['coverage'] != 4) & (df['coverage'] != 5)
df['mcaid_elig_exante'] = (mcaid_elig).astype(int)
return df['mcaid_elig_exante']
[docs] def determine_elig(self, df):
"""
input : a form of hieu_table, with fpl variable available
output: the data frame of the same hieu_table with mcaid_elig column
and medicaid premium as well
# adjusted_prev_elig = previously elig, without ACA, from input data
# predicted_elig = predicted probability, from input data
# mcaid_elig = everyone who eligible post-ACA without prediction model
# newly_elig = with ACA, calculated
"""
mcaid_elig = False
for index, row in self.curr_data_me.iterrows():
# true medicaid eligibility
if row['doc']==1:
eligTemp = (df['doc_status'] <= 2) & (df['age']>=row['min_age']) & (df['age'] <= row['max_age']) & \
(df['fpl'] <= row['fpl_thresh'])
loc_ind_adult_child = np.where((df['person_type'] > 3) & (df['tax_dependent'] == 0))[0]
eligTemp[loc_ind_adult_child] = (df.loc[loc_ind_adult_child, 'doc_status'] <= 2) & ( df.loc[loc_ind_adult_child, 'age'] >= row['min_age']) & (df.loc[loc_ind_adult_child, 'age'] <= row['max_age']) & \
(df.loc[loc_ind_adult_child, 'ind_fpl'] <= row['fpl_thresh'])
else:
eligTemp = (df['age']>=row['min_age']) & (df['age'] <= row['max_age']) & (df['fpl']<=row['fpl_thresh'])
loc_ind_adult_child = np.where((df['person_type'] > 3) & (df['tax_dependent'] == 0))[0]
eligTemp[loc_ind_adult_child]= ( df.loc[loc_ind_adult_child, 'age'] >= row['min_age']) & (df.loc[loc_ind_adult_child, 'age'] <= row['max_age']) & (df.loc[loc_ind_adult_child, 'ind_fpl'] <= row['fpl_thresh'])
# calculate newly eligible persons
mcaid_elig = mcaid_elig | eligTemp
df['new_mcaid_elig'] = (mcaid_elig & (df['coverage'] != 3) & (df['coverage'] != 4) & (df['coverage'] != 5) \
& (df['mcaid_elig_exante']==0)).fillna(False).astype(int)
# total eligible persons include newly eligible + previously eligible persons
df['mcaid_elig'] = (df['new_mcaid_elig'] | df['mcaid_elig_exante'] | df['gvmt_insurance']==1).astype(int)
# disable the individuals who are subisdy eligible on mcaid
#if 'subsidy_elig' in df:
# df['mcaid_elig'] = df['mcaid_elig'] & (~df['subsidy_elig'])
# calculate eligible persons based on prediction model
df['pass_threshold'] = self.pass_threshold(self.mcaid_threshold, df['mcaid_predict'])
df['predicted_elig'] = ( (df['doc_status'] <= 2) & (df['pass_threshold'] == True) & (df['coverage'] != 3) & (df['coverage'] != 4) & ( df['coverage'] != 5) & (df['age'] > 18)).astype(int)
elig_fam = np.array(df.loc[df['predicted_elig'] == 1]['hieu_id'].drop_duplicates())
# make their family members eligible IF they are documented and not on other public, medicare
df_prdt = df.loc[(df['hieu_id'].isin(elig_fam)) & (df['doc_status'] <= 2) & (df['coverage'] != 3) & (df['coverage'] != 4) & (df['coverage'] != 5)]
df_prdt['predicted_elig'] = 1
df['predicted_exante_elig'] = False
# make children exante predicted eligible
df['predicted_exante_elig']=False
df_prdt2 = df_prdt.loc[(df_prdt['person_type'] == 2) | (df_prdt['person_type'] == 3)& (df_prdt['coverage'] != 3) & (df_prdt['coverage'] != 4) & (df_prdt['coverage'] != 5)]
df_prdt2['predicted_exante_elig'] = True
df.update(df_prdt2['predicted_exante_elig'])
df.update(df_prdt['predicted_elig'])
return df
[docs] def calculate_premium(self, df, shadow_premium):
"""
assuming df has mcaid_elig variable
# pseudo-code:
if xc_sub then msp = a0
else
if newly_elig then msp = a1
else if prev_elig then msp = a2
else if predicted elig then msp = a3
"""
# for xc_sub elig, shadow premium applied will be a0
xc_sub_elig = df.loc[df['subsidy_elig'] == 1]
xc_sub_elig['shadow_premium'] = shadow_premium[0]
# for the rest: a1, a2, a3
xc_not_elig = df.loc[df['subsidy_elig'] == 0]
xc_sub1 = xc_not_elig.loc[xc_not_elig['new_mcaid_elig'] == 1]
xc_sub1['shadow_premium'] = shadow_premium[1]
xc_sub2 = xc_not_elig.loc[(xc_not_elig['new_mcaid_elig'] == 0) & (xc_not_elig['mcaid_elig_exante'] == 1)]
xc_sub2['shadow_premium'] = shadow_premium[2]
xc_sub3 = xc_not_elig.loc[(xc_not_elig['new_mcaid_elig'] == 0) & (xc_not_elig['mcaid_elig_exante'] == 0) & \
(xc_not_elig['predicted_elig'] == 1)]
xc_sub3['shadow_premium'] = shadow_premium[3]
updated_df = pd.concat([xc_sub_elig, xc_sub1, xc_sub2, xc_sub3])
df['shadow_premium'] = 0
df.update(updated_df)
df['mcaid_prem'] = 0
for index, row in self.curr_data_me.iterrows():
if not math.isnan(row['premium']):
premFlag = ((df['mcaid_elig'] == 1) & (df['age'] >= row['min_age']) & (df['age'] <= row['max_age']) & \
(df['fpl'] <= row['fpl_thresh']) & (df['fpl'] >= row['premium_thresh'])).astype(int)
premTemp = premFlag * row['premium']*12
# premium is presented as monthly, need to convert to annual [xc, 4/19/2018]
df['mcaid_prem'] = df['mcaid_prem'] + premTemp + df['shadow_premium']
return df['mcaid_prem']