def test_incorrect_Calculator_instantiation(pit_subsample, cit_crosssample): pol = Policy() rec = Records(data=pit_subsample) crec = CorpRecords(data=cit_crosssample) with pytest.raises(ValueError): Calculator(policy=None, records=rec, corprecords=crec) with pytest.raises(ValueError): Calculator(policy=pol, records=None, corprecords=crec) with pytest.raises(ValueError): Policy(num_years=0)
def test_validity_of_name_lists(): assert len(DIST_TABLE_COLUMNS) == len(DIST_TABLE_LABELS) records_varinfo = Records(data=None) assert set(DIST_VARIABLES).issubset(records_varinfo.CALCULATED_VARS | {'s006', 'XTOT'}) extra_vars_set = set(['count', 'count_StandardDed', 'count_ItemDed', 'count_AMT']) assert (set(DIST_TABLE_COLUMNS) - set(DIST_VARIABLES)) == extra_vars_set
def test_create_tables(): # create a current-law Policy object and Calculator object calc1 policy1 = Policy() records1 = Records(data=TAXDATA, weights=WEIGHTS, start_year=2009) calc1 = Calculator(policy=policy1, records=records1) calc1.calc_all() # create a policy-reform Policy object and Calculator object calc2 reform = {2013: {'_II_rt4': [0.56]}} policy2 = Policy() policy2.implement_reform(reform) records2 = Records(data=TAXDATA, weights=WEIGHTS, start_year=2009) calc2 = Calculator(policy=policy2, records=records2) calc2.calc_all() # create various distribution tables t2 = create_distribution_table(calc2, groupby="small_income_bins", result_type="weighted_sum") tdiff = create_difference_table(calc1, calc2, groupby="large_income_bins") tdiff_webapp = create_difference_table(calc1, calc2, groupby="webapp_income_bins")
def test_correct_Records_instantiation(puf_1991, puf_1991_path, weights_1991): rec1 = Records(data=puf_1991_path, gfactors=None, weights=weights_1991) assert rec1 assert np.all(rec1.MARS != 0) assert rec1.current_year == Records.PUF_YEAR sum_e00200_in_puf_year = rec1.e00200.sum() rec1.set_current_year(Records.PUF_YEAR + 1) sum_e00200_in_puf_year_plus_one = rec1.e00200.sum() assert sum_e00200_in_puf_year_plus_one == sum_e00200_in_puf_year rec2 = Records(data=puf_1991, gfactors=Growfactors(), weights=None) assert rec2 assert np.all(rec2.MARS != 0) assert rec2.current_year == Records.PUF_YEAR adj_df = pd.read_csv(Records.ADJUST_RATIOS_PATH) adj_df = adj_df.transpose() rec3 = Records(data=puf_1991, weights=None, adjust_ratios=adj_df) assert rec3 assert np.all(rec3.MARS != 0) assert rec3.current_year == Records.PUF_YEAR
def test_default_rates_and_those_implied_by_blowup_factors(): """ Check that default GDP growth rates, default wage growth rates, and default price inflation rates, are consistent with the rates embedded in the Records blowup factors (BF). """ record = Records(TAXDATA_PATH) # contains the blowup factors policy = Policy() # contains the default indexing rates syr = Policy.JSON_START_YEAR endyr = Policy.FIRST_BUDGET_YEAR + Policy.NUM_BUDGET_YEARS nyrs = endyr - syr # back out original stage I GDP growth rates from blowup factors record.BF.AGDPN[Records.PUF_YEAR] = 1 for year in range(Records.PUF_YEAR + 1, endyr): record.BF.AGDPN[year] = (record.BF.AGDPN[year] * record.BF.AGDPN[year - 1] * record.BF.APOPN[year]) # calculate nominal GDP growth rates from original GDP growth rates nominal_rates = np.zeros(nyrs) for year in range(syr, endyr): irate = policy._inflation_rates[year - syr] nominal_rates[year - syr] = ( record.BF.AGDPN[year] / record.BF.AGDPN[year - 1] - 1 - irate) # check that nominal_rates are same as default GDP growth rates nominal_rates = np.round(nominal_rates, 4) assert_array_equal(nominal_rates, Growth.REAL_GDP_GROWTH_RATES) # back out stage I inflation rates from blowup factors cpi_u = np.zeros(nyrs) for year in range(syr, endyr): cpi_u[year - syr] = record.BF.ACPIU[year] - 1 # check that blowup rates are same as default inflation rates cpi_u = np.round(cpi_u, 4) assert_array_equal(cpi_u, policy._inflation_rates) # back out original stage I wage growth rates from blowup factors record.BF.AWAGE[Records.PUF_YEAR] = 1 for year in range(Records.PUF_YEAR + 1, endyr): record.BF.AWAGE[year] = (record.BF.AWAGE[year] * record.BF.AWAGE[year - 1] * record.BF.APOPN[year]) # calculate nominal wage growth rates from original wage growth rates wage_growth_rates = np.zeros(nyrs) for year in range(syr, endyr): wage_growth_rates[year - syr] = ( record.BF.AWAGE[year] / record.BF.AWAGE[year - 1] - 1) # check that blowup rates are same as default wage growth rates wage_growth_rates = np.round(wage_growth_rates, 4) assert_array_equal(wage_growth_rates, policy._wage_growth_rates)
def test_mtr_pt_active(puf_subsample): """ Test whether including wages in active income causes MTRs on e00900p and e26270 to be less than -1 (i.e., -100%) """ # pylint: disable=too-many-locals rec = Records(data=puf_subsample) reform_year = 2018 # create current-law Calculator object, calc1 pol1 = Policy() calc1 = Calculator(policy=pol1, records=rec) calc1.advance_to_year(reform_year) calc1.calc_all() mtr1_e00900p = calc1.mtr('e00900p')[2] mtr1_e26270 = calc1.mtr('e26270')[2] assert min(mtr1_e00900p) > -1 assert min(mtr1_e26270) > -1 # change PT rates, calc2 reform2 = {reform_year: {'_PT_rt7': [0.35]}} pol2 = Policy() pol2.implement_reform(reform2) calc2 = Calculator(policy=pol2, records=rec) calc2.advance_to_year(reform_year) calc2.calc_all() mtr2_e00900p = calc2.mtr('e00900p')[2] mtr2_e26270 = calc2.mtr('e26270')[2] assert min(mtr2_e00900p) > -1 assert min(mtr2_e26270) > -1 # change PT_wages_active_income reform3 = {reform_year: {'_PT_wages_active_income': [True]}} pol3 = Policy() pol3.implement_reform(reform3) calc3 = Calculator(policy=pol3, records=rec) calc3.advance_to_year(reform_year) calc3.calc_all() mtr3_e00900p = calc3.mtr('e00900p')[2] mtr3_e26270 = calc3.mtr('e26270')[2] assert min(mtr3_e00900p) > -1 assert min(mtr3_e26270) > -1 # change PT rates and PT_wages_active_income reform4 = { reform_year: { '_PT_wages_active_income': [True], '_PT_rt7': [0.35] } } pol4 = Policy() pol4.implement_reform(reform4) calc4 = Calculator(policy=pol4, records=rec) calc4.advance_to_year(reform_year) calc4.calc_all() mtr4_e00900p = calc4.mtr('e00900p')[2] mtr4_e26270 = calc4.mtr('e26270')[2] assert min(mtr4_e00900p) > -1 assert min(mtr4_e26270) > -1
def create_base_table(test_path): """ Create and return base table. """ # specify calculated variable names and descriptions calc_dict = {'eitc': 'Federal EITC', 'iitax': 'Federal income tax liability', 'payrolltax': 'Payroll taxes (ee+er) for OASDI+HI', 'c00100': 'Federal AGI', 'c02500': 'OASDI benefits in AGI', 'c04600': 'Post-phase-out personal exemption', 'c21040': 'Itemized deduction that is phased out', 'c04470': 'Post-phase-out itemized deduction', 'c04800': 'Federal regular taxable income', 'c05200': 'Regular tax on taxable income', 'c07220': 'Child tax credit (adjusted)', 'c11070': 'Extra child tax credit (refunded)', 'c07180': 'Child care credit', 'c09600': 'Federal AMT liability'} # specify read variable names and descriptions unused_var_set = set(['DSI', 'EIC', 'h_seq', 'a_lineno', 'ffpos', 'fips', 'agi_bin', 'FLPDYR', 'FLPDMO', 'f2441', 'f3800', 'f6251', 'f8582', 'f8606', 'f8829', 'f8910', 'f8936', 'n20', 'n24', 'n25', 'n30', 'PREP', 'SCHB', 'SCHCF', 'SCHE', 'TFORM', 'IE', 'TXST', 'XFPT', 'XFST', 'XOCAH', 'XOCAWH', 'XOODEP', 'XOPAR', 'XTOT', 'MARS', 'MIDR', 'RECID', 'gender', 'wage_head', 'wage_spouse', 'earnsplit', 'agedp1', 'agedp2', 'agedp3', 's006', 's008', 's009', 'WSAMP', 'TXRT', 'matched_weight', 'e00200p', 'e00200s', 'e00900p', 'e00900s', 'e02100p', 'e02100s', 'age_head', 'age_spouse', 'nu18', 'n1820', 'n21', 'ssi_ben', 'snap_ben', 'other_ben', 'mcare_ben', 'mcaid_ben', 'vet_ben', 'housing_ben', 'tanf_ben', 'wic_ben', 'blind_head', 'blind_spouse']) records_varinfo = Records(data=None) read_vars = list(records_varinfo.USABLE_READ_VARS - unused_var_set) # get read variable information from JSON file rec_vars_path = os.path.join(test_path, '..', 'records_variables.json') with open(rec_vars_path) as rvfile: read_var_dict = json.load(rvfile) # create table_dict with sorted read vars followed by sorted calc vars table_dict = dict() for var in sorted(read_vars): table_dict[var] = read_var_dict['read'][var]['desc'] sorted_calc_vars = sorted(calc_dict.keys()) for var in sorted_calc_vars: table_dict[var] = calc_dict[var] # construct DataFrame table from table_dict table = pd.DataFrame.from_dict(table_dict, orient='index') table.columns = ['description'] return table
def test_Calculator_create_difference_table(puf_1991, weights_1991): # create current-law Policy object and use to create Calculator calc1 policy1 = Policy() puf1 = Records(data=puf_1991, weights=weights_1991, start_year=2009) calc1 = Calculator(policy=policy1, records=puf1) calc1.advance_to_year(2013) calc1.calc_all() # create policy-reform Policy object and use to create Calculator calc2 policy2 = Policy() reform = {2013: {'_II_rt7': [0.45]}} policy2.implement_reform(reform) puf2 = Records(data=puf_1991, weights=weights_1991, start_year=2009) calc2 = Calculator(policy=policy2, records=puf2) calc2.advance_to_year(2013) calc2.calc_all() # create difference table and check that it is a Pandas DataFrame dtable = create_difference_table(calc1.records, calc2.records, groupby="weighted_deciles") assert isinstance(dtable, pd.DataFrame)
def test_dist_table_sum_row(pit_subsample, cit_crosssample): rec = Records(data=pit_subsample) crec = CorpRecords(data=cit_crosssample) calc = Calculator(policy=Policy(), records=rec, corprecords=crec) calc.calc_all() tb1 = create_distribution_table(calc.distribution_table_dataframe(), 'standard_income_bins', 'GTI') tb2 = create_distribution_table(calc.distribution_table_dataframe(), 'weighted_deciles', 'GTI') allrow1 = tb1[-1:] allrow2 = tb2[-4:-3] assert np.allclose(allrow1, allrow2)
def reform_results(reform_dict, puf_data, reform_2017_law): """ Return actual results of the reform specified in reform_dict. """ # pylint: disable=too-many-locals rec = Records(data=puf_data) # create baseline Calculator object, calc1 pol = Policy() if reform_dict['baseline'] == '2017_law.json': pol.implement_reform(reform_2017_law) elif reform_dict['baseline'] == 'current_law_policy.json': pass else: msg = 'illegal baseline value {}' raise ValueError(msg.format(reform_dict['baseline'])) calc1 = Calculator(policy=pol, records=rec, verbose=False, behavior=None) # create reform Calculator object, calc2, with possible behavioral response start_year = reform_dict['start_year'] beh = Behavior() if '_BE_cg' in reform_dict['value']: elasticity = reform_dict['value']['_BE_cg'] del reform_dict['value']['_BE_cg'] # in order to have a valid reform beh_assump = {start_year: {'_BE_cg': elasticity}} beh.update_behavior(beh_assump) reform = {start_year: reform_dict['value']} pol.implement_reform(reform) calc2 = Calculator(policy=pol, records=rec, verbose=False, behavior=beh) # increment both Calculator objects to reform's start_year calc1.advance_to_year(start_year) calc2.advance_to_year(start_year) # calculate prereform and postreform output for several years output_type = reform_dict['output_type'] num_years = 4 results = list() for _ in range(0, num_years): calc1.calc_all() prereform = calc1.array(output_type) if calc2.behavior_has_response(): calc2_br = Behavior.response(calc1, calc2) postreform = calc2_br.array(output_type) else: calc2.calc_all() postreform = calc2.array(output_type) diff = postreform - prereform weighted_sum_diff = (diff * calc1.array('s006')).sum() * 1.0e-9 results.append(weighted_sum_diff) calc1.increment_year() calc2.increment_year() # write actual results to actual_str actual_str = 'Tax-Calculator' for iyr in range(0, num_years): actual_str += ',{:.1f}'.format(results[iyr]) return actual_str
def test_dropq_with_full_puf(puf_path): # specify usermods dictionary in code fyr = 2016 reforms = dict() reforms['_II_rt4'] = [0.39, 0.40, 0.41] reforms['_PT_rt4'] = [0.39, 0.40, 0.41] reforms['_II_rt3'] = [0.31, 0.32, 0.33] reforms['_PT_rt3'] = [0.31, 0.32, 0.33] usermods = dict() usermods['policy'] = {fyr: reforms} usermods['consumption'] = {} usermods['behavior'] = {} usermods['growdiff_baseline'] = {} usermods['growdiff_response'] = {} usermods['gdp_elasticity'] = {} # create a Policy object (clp) containing current-law policy parameters clp = Policy() clp.implement_reform(usermods['policy']) # create a Records object (rec) containing all puf.csv input records rec = Records(data=puf_path) # create a Calculator object using clp policy and puf records calc = Calculator(policy=clp, records=rec) calc.increment_year() calc.increment_year() calc.increment_year() # create aggregate diagnostic table (adt) as a Pandas DataFrame object nyrs = 2 adt = multiyear_diagnostic_table(calc, nyrs) taxes_fullsample = adt.loc["Combined Liability ($b)"] assert taxes_fullsample is not None # create a Public Use File object tax_data = pd.read_csv(puf_path) # call dropq.run_model (mY_dec, _, _, _, _, _, _, _, _, _, fiscal_tots) = dropq.run_model(tax_data, start_year=fyr, user_mods=usermods, return_json=False, num_years=nyrs) fulls_reform_revenue = taxes_fullsample.loc[fyr] dropq_reform_revenue = mY_dec['_combined_dec_0'].loc['sums'] dropq_reform_revenue *= 1e-9 # convert to billions of dollars diff = abs(fulls_reform_revenue - dropq_reform_revenue) # assert that dropq revenue is similar to the fullsample calculation assert diff / fulls_reform_revenue < 0.01 # assert that Reform - Baseline = Reported Delta delta_yr0 = fiscal_tots[0] baseline_yr0 = fiscal_tots[1] reform_yr0 = fiscal_tots[2] diff_yr0 = (reform_yr0.loc['combined_tax'] - baseline_yr0.loc['combined_tax']).values delta_yr0 = delta_yr0.loc['combined_tax'].values npt.assert_allclose(diff_yr0, delta_yr0)
def initiate_calculator(self): """ Creates an intial version of the taxcalc.Calculator object for 2014 """ policy1 = Policy() records1 = Records(data=self.records_data) if self.refdict != {}: policy1.implement_reform(self.refdict) calc1 = Calculator(records=records1, policy=policy1, verbose=False) calc1.advance_to_year(2014) calc1.calc_all() return (calc1)
def taxcalc_clp_results(): """ Use taxcalc package on this computer to compute aggregate income tax and payroll tax revenues for years beginning with MIN_START_YEAR and ending with MAX_START_YEAR+NUMBER_OF_YEARS-1 for current-law policy. Return two aggregate revenue dictionaries indexed by calendar year. """ calc = Calculator(policy=Policy(), records=Records(data=PUF_PATH)) nyrs = MAX_START_YEAR + NUMBER_OF_YEARS - MIN_START_YEAR adt = calc.diagnostic_table(num_years=nyrs) # note that adt is Pandas DataFrame object return (adt.xs('Ind inc tax ($b)').to_dict(), adt.xs('Payroll tax ($b)').to_dict())
def test_diff_table_sum_row(): # create a current-law Policy object and Calculator calc1 policy1 = Policy() records1 = Records(data=TAXDATA, weights=WEIGHTS, start_year=2009) calc1 = Calculator(policy=policy1, records=records1) calc1.calc_all() # create a policy-reform Policy object and Calculator calc2 reform = {2013: {'_II_rt4': [0.56]}} policy2 = Policy() policy2.implement_reform(reform) records2 = Records(data=TAXDATA, weights=WEIGHTS, start_year=2009) calc2 = Calculator(policy=policy2, records=records2) calc2.calc_all() # create two difference tables and compare their content tdiff1 = create_difference_table(calc1, calc2, groupby="small_income_bins") tdiff2 = create_difference_table(calc1, calc2, groupby="large_income_bins") non_digit_cols = ['mean', 'perc_inc', 'perc_cut', 'share_of_change'] digit_cols = [x for x in tdiff1.columns.tolist() if x not in non_digit_cols] assert np.allclose(tdiff1[digit_cols][-1:], tdiff2[digit_cols][-1:]) assert np.array_equal(tdiff1[non_digit_cols][-1:], tdiff2[non_digit_cols][-1:])
def test_calc_all(): """ Test calc_all method. """ cyr = 2016 pol = Policy() pol.set_year(cyr) nonstd = Records(data=pd.read_csv(StringIO(RAWINPUT_CONTENTS)), start_year=cyr, gfactors=None, weights=None) assert nonstd.array_length == RAWINPUT_FUNITS calc = Calculator(policy=pol, records=nonstd, sync_years=False) # keeps raw data unchanged assert calc.current_year == cyr
def test_calc_all(reform_file, rawinputfile): cyr = 2016 pol = Policy() param_dict = Calculator.read_json_param_objects(reform_file.name, None) pol.implement_reform(param_dict['policy']) pol.set_year(cyr) nonstd = Records(data=rawinputfile.name, gfactors=None, weights=None, start_year=cyr) assert nonstd.array_length == RAWINPUTFILE_FUNITS calc = Calculator(policy=pol, records=nonstd, sync_years=False) # keeps raw data unchanged assert calc.current_year == cyr calc.calc_all()
def test_row_classifier(): # create a current-law Policy object and Calculator calc1 policy1 = Policy() records1 = Records(data=TAXDATA, weights=WEIGHTS, start_year=2009) calc1 = Calculator(policy=policy1, records=records1) calc1.calc_all() calc1_s006 = create_distribution_table(calc1, groupby="webapp_income_bins", result_type="weighted_sum").s006 # create a policy-reform Policy object and Calculator calc2 reform = {2013: {"_ALD_StudentLoan_HC": [1]}} policy2 = Policy() policy2.implement_reform(reform) records2 = Records(data=TAXDATA, weights=WEIGHTS, start_year=2009) calc2 = Calculator(policy=policy2, records=records2) calc2.calc_all() calc2_s006 = create_distribution_table(calc2, groupby="webapp_income_bins", result_type="weighted_sum", baseline_calc=calc1).s006 # use weighted sum of weights in each cell to check classifer npt.assert_array_equal(calc1_s006, calc2_s006)
def test_row_classifier(puf_1991, weights_1991): # create a current-law Policy object and Calculator calc1 policy1 = Policy() records1 = Records(data=puf_1991, weights=weights_1991, start_year=2009) calc1 = Calculator(policy=policy1, records=records1) calc1.calc_all() calc1_s006 = create_distribution_table(calc1.records, groupby='webapp_income_bins', result_type='weighted_sum').s006 # create a policy-reform Policy object and Calculator calc2 reform = {2013: {'_ALD_StudentLoan_hc': [1]}} policy2 = Policy() policy2.implement_reform(reform) records2 = Records(data=puf_1991, weights=weights_1991, start_year=2009) calc2 = Calculator(policy=policy2, records=records2) calc2.calc_all() calc2_s006 = create_distribution_table(calc2.records, groupby='webapp_income_bins', result_type='weighted_sum', baseline_obj=calc1.records).s006 # use weighted sum of weights in each cell to check classifer npt.assert_array_equal(calc1_s006, calc2_s006)
def main(taxyear, rnseed, ssize): """ Contains high-level logic of the script. """ # read puf.csv file into a Pandas DataFrame current_path = os.path.abspath(os.path.dirname(__file__)) pufcsv_filename = os.path.join(current_path, '..', '..', 'puf.csv') if not os.path.isfile(pufcsv_filename): msg = 'ERROR: puf.csv file not found in top-level directory' sys.stderr.write(msg + '\n') return 1 xdf = pd.read_csv(pufcsv_filename) # remove xdf variables not needed in xYY.csv file records_varinfo = Records(data=None) if TRACE: info = 'df.shape before dropping = {}'.format(xdf.shape) sys.stdout.write(info + '\n') for var in DROP_VARS: if var not in records_varinfo.USABLE_READ_VARS: msg = 'ERROR: variable {} already dropped'.format(var) sys.stderr.write(msg + '\n') return 1 xdf.drop(var, axis=1, inplace=True) if TRACE: info = 'df.shape after dropping = {}'.format(xdf.shape) sys.stdout.write(info + '\n') # add random amounts to xdf variables randomize_data(xdf, taxyear, rnseed) # constrain values of certain variables as required by Records class constrain_data(xdf) # sample xdf without replacement to get ssize observations if DEBUG: (sample_size, _) = xdf.shape xxdf = xdf else: sample_size = ssize xxdf = xdf.sample(n=sample_size, random_state=rnseed) xxdf['RECID'] = [rid + 1 for rid in range(sample_size)] if TRACE: info = 'df.shape after sampling = {}'.format(xxdf.shape) sys.stdout.write(info + '\n') # write randomized and sampled xxdf to xYY.csv file xxdf.to_csv('x{}.csv'.format(taxyear % 100), index=False) # normal return code return 0
def test_credit_reforms(puf_path): # pylint: disable=redefined-outer-name """ Test personal credit reforms using small puf.csv sub-sample """ # pylint: disable=too-many-locals reform_year = 2017 fullsample = pd.read_csv(puf_path) subsample = fullsample.sample( frac=0.05, # pylint: disable=no-member random_state=180) # create current-law Calculator object, calc1 recs1 = Records(data=subsample) calc1 = Calculator(policy=Policy(), records=recs1) calc1.advance_to_year(reform_year) calc1.calc_all() itax1 = (calc1.records.iitax * calc1.records.s006).sum() # create personal-refundable-credit-reform Calculator object, calc2 recs2 = Records(data=subsample) policy2 = Policy() reform = {reform_year: {'_II_credit': [[1000, 1000, 1000, 1000, 1000]]}} policy2.implement_reform(reform) calc2 = Calculator(policy=policy2, records=recs2) calc2.advance_to_year(reform_year) calc2.calc_all() itax2 = (calc2.records.iitax * calc2.records.s006).sum() # create personal-nonrefundable-credit-reform Calculator object, calc3 recs3 = Records(data=subsample) policy3 = Policy() reform = {reform_year: {'_II_credit_nr': [[1000, 1000, 1000, 1000, 1000]]}} policy3.implement_reform(reform) calc3 = Calculator(policy=policy3, records=recs3) calc3.advance_to_year(reform_year) calc3.calc_all() itax3 = (calc3.records.iitax * calc3.records.s006).sum() # check income tax revenues generated by the three Calculator objects assert itax2 < itax1 # because refundable credits lower revenues assert itax3 > itax2 # because nonrefundable credits lower revenues less assert itax3 < itax1 # because nonrefundable credits lower revenues some
def test_ID_HC_vs_BS(puf_1991, weights_1991): """ Test that complete haircut of itemized deductions produces same results as a 100% benefit surtax with no benefit deduction. """ # specify complete-haircut reform policy and Calculator object hc_reform = { 2013: { '_ID_Medical_hc': [1.0], '_ID_StateLocalTax_hc': [1.0], '_ID_RealEstate_hc': [1.0], '_ID_Casualty_hc': [1.0], '_ID_Miscellaneous_hc': [1.0], '_ID_InterestPaid_hc': [1.0], '_ID_Charity_hc': [1.0] } } hc_policy = Policy() hc_policy.implement_reform(hc_reform) hc_records = Records(data=puf_1991, weights=weights_1991, start_year=2009) hc_calc = Calculator(policy=hc_policy, records=hc_records) # specify benefit-surtax reform policy and Calculator object bs_reform = { 2013: { '_ID_BenefitSurtax_crt': [0.0], '_ID_BenefitSurtax_trt': [1.0] } } bs_policy = Policy() bs_policy.implement_reform(bs_reform) bs_records = Records(data=puf_1991, weights=weights_1991, start_year=2009) bs_calc = Calculator(policy=bs_policy, records=bs_records) # compare calculated tax results generated by the two reforms hc_calc.calc_all() bs_calc.calc_all() assert np.allclose(hc_calc.records._payrolltax, bs_calc.records._payrolltax) assert np.allclose(hc_calc.records._iitax, bs_calc.records._iitax)
def test_percentage_change_gdp(): policy1 = Policy() records1 = Records(data=TAXDATA, weights=WEIGHTS, start_year=2009) calc1 = Calculator(policy=policy1, records=records1) calc1.calc_all() reform = { 2013: { "_STD": [[12600, 25200, 12600, 18600, 25300, 12600, 2100]], "_AMT_trt1": [0.0], "_AMT_trt2": [0.0] } } policy2 = Policy() policy2.implement_reform(reform) records2 = Records(data=TAXDATA, weights=WEIGHTS, start_year=2009) calc2 = Calculator(policy=policy2, records=records2) calc2.calc_all() gdp_diff = percentage_change_gdp(calc1, calc2, elasticity=0.36) assert gdp_diff > 0
def test_puf_var_stats(tests_path, puf_fullsample): """ Main logic of test. """ # create a baseline Policy object containing 2017_law.json parameters pre_tcja_jrf = os.path.join(tests_path, '..', 'reforms', '2017_law.json') pre_tcja = Calculator.read_json_param_objects(pre_tcja_jrf, None) baseline_policy = Policy() baseline_policy.implement_reform(pre_tcja['policy']) # create a Calculator object using baseline_policy and full puf.csv sample rec = Records(data=puf_fullsample) calc = Calculator(policy=baseline_policy, records=rec, verbose=False) # create base tables table_mean = create_base_table(tests_path) table_corr = copy.deepcopy(table_mean) del table_corr['description'] # add statistics to tables year_headers = ['description'] for year in range(Policy.JSON_START_YEAR, Policy.LAST_BUDGET_YEAR + 1): assert year == calc.policy_current_year() year_headers.append(str(year)) calc.calc_all() calculate_mean_stats(calc, table_mean, year) if year == 2016: calculate_corr_stats(calc, table_corr) if year < Policy.LAST_BUDGET_YEAR: calc.increment_year() # write tables to new CSV files mean_path = os.path.join(tests_path, MEAN_FILENAME + '-new') table_mean.sort_index(inplace=True) table_mean.to_csv(mean_path, header=year_headers, float_format='%8.0f') corr_path = os.path.join(tests_path, CORR_FILENAME + '-new') table_corr.sort_index(inplace=True) table_corr.to_csv(corr_path, float_format='%8.2f', columns=table_corr.index) # compare new and old CSV files for nonsmall differences if sys.version_info.major == 2: # tighter tests for Python 2.7 mean_msg = differences(mean_path, mean_path[:-4], 'MEAN', small=0.0) corr_msg = differences(corr_path, corr_path[:-4], 'CORR', small=0.0) else: # looser tests for Python 3.6 mean_msg = differences(mean_path, mean_path[:-4], 'MEAN', small=1.0) corr_msg = differences(corr_path, corr_path[:-4], 'CORR', small=0.01) if mean_msg or corr_msg: raise ValueError(mean_msg + corr_msg)
def _calc_object(self, exact_calcs, emulate_taxsim_2441_logic, output_records): """ Create and return Calculator object to conduct the tax calculations. Parameters ---------- exact_calcs: boolean emulate_taxsim_2441_logic: boolean output_records: boolean Returns ------- calc: Calculator """ # create all-zeros dictionary and then list of all-zero dictionaries Records.read_var_info() zero_dict = {} for varname in Records.USABLE_READ_VARS: zero_dict[varname] = 0 dict_list = [zero_dict for _ in range(0, len(self._input))] # use dict_list to create a Pandas DataFrame and Records object recsdf = pd.DataFrame(dict_list, dtype='int64') recsdf['MARS'] = recsdf['MARS'].add(1) # because MARS==0 is illegal recs = Records(data=recsdf, exact_calculations=exact_calcs, gfactors=None, weights=None, start_year=self.policy.start_year) assert recs.array_length == len(self._input) # specify input for each tax filing unit in Records object lnum = 0 for idx in range(0, recs.array_length): lnum += 1 SimpleTaxIO._specify_input(recs, idx, self._input[lnum], emulate_taxsim_2441_logic) # optionally write Records.USABLE_READ_VARS content to file if output_records: recdf = pd.DataFrame() for varname in Records.USABLE_READ_VARS: vardata = getattr(recs, varname) recdf[varname] = vardata recdf.to_csv(re.sub('out-simtax', 'records', self._output_filename), float_format='%.2f', index=False) # create Calculator object containing all tax filing units return Calculator(policy=self.policy, records=recs, sync_years=False)
def test_dist_table_sum_row(): # Create a default Policy object policy1 = Policy() records1 = Records(data=TAXDATA, weights=WEIGHTS, start_year=2009) # Create a Calculator calc1 = Calculator(policy=policy1, records=records1) calc1.calc_all() t1 = create_distribution_table(calc1, groupby="small_income_bins", result_type="weighted_sum") t2 = create_distribution_table(calc1, groupby="large_income_bins", result_type="weighted_sum") assert np.allclose(t1[-1:], t2[-1:]) t3 = create_distribution_table(calc1, groupby="small_income_bins", result_type="weighted_avg")
def test_adjustment(): # make calculator records_y = Records(data=TAXDATA, weights=WEIGHTS, start_year=2009) policy_y = Policy() calc_y = Calculator(policy=policy_y, records=records_y) ATXPY_pre = calc_y.records.BF.ATXPY[2015] AGDPN_pre = calc_y.records.BF.AGDPN[2015] # apply adjustment adjustment(calc_y, 0.01, 2015) assert calc_y.records.BF.AGDPN[2015] == AGDPN_pre + 0.01 assert calc_y.records.BF.ATXPY[2015] == ATXPY_pre + 0.01
def test_consumption_response(puf_1991, weights_1991): consump = Consumption() mpc = 0.5 consumption_response = {2013: {'_MPC_e20400': [mpc]}} consump.update_consumption(consumption_response) # test incorrect call to response method with pytest.raises(ValueError): consump.response(list(), 1) # test correct call to response method recs = Records(data=puf_1991, weights=weights_1991, start_year=2009) pre = copy.deepcopy(recs.e20400) consump.response(recs, 1.0) post = recs.e20400 actual_diff = post - pre expected_diff = np.ones(recs.dim) * mpc assert np.allclose(actual_diff, expected_diff) # compute earnings mtr with no consumption response recs0 = Records(data=puf_1991, weights=weights_1991, start_year=2009) calc0 = Calculator(policy=Policy(), records=recs0, consumption=None) ided0 = copy.deepcopy(recs0.e20400) (mtr0_ptax, mtr0_itax, _) = calc0.mtr(variable_str='e00200p', wrt_full_compensation=False) assert np.allclose(calc0.records.e20400, ided0) # compute earnings mtr with consumption response recs1 = Records(data=puf_1991, weights=weights_1991, start_year=2009) calc1 = Calculator(policy=Policy(), records=recs1, consumption=None) assert np.allclose(calc1.records.e20400, ided0) calc1.consumption.update_consumption(consumption_response) (mtr1_ptax, mtr1_itax, _) = calc1.mtr(variable_str='e00200p', wrt_full_compensation=False) assert np.allclose(calc1.records.e20400, ided0) # confirm that payroll mtr values are no different assert np.allclose(mtr1_ptax, mtr0_ptax) # confirm that all mtr with cons-resp are no greater than without cons-resp assert np.all(np.less_equal(mtr1_itax, mtr0_itax)) # confirm that some mtr with cons-resp are less than without cons-resp assert np.any(np.less(mtr1_itax, mtr0_itax))
def test_update_growth(): records_x = Records(data=TAXDATA, weights=WEIGHTS, start_year=2009) records_y = Records(data=TAXDATA, weights=WEIGHTS, start_year=2009) policy_x = Policy() policy_y = Policy() # change growth adjustment/target growth_x = Growth() factor_x = {2015: {'_factor_target': [0.04]}} growth_x.update_economic_growth(factor_x) growth_y = Growth() factor_y = {2015: {'_factor_adjustment': [0.01]}} growth_y.update_economic_growth(factor_y) # create two Calculators calc_x = Calculator(policy=policy_x, records=records_x, growth=growth_x) calc_y = Calculator(policy=policy_y, records=records_y, growth=growth_y) assert_array_equal(calc_x.growth.factor_target, growth_x.factor_target) assert_array_equal( calc_x.growth._factor_target, np.array([ 0.0226, 0.0241, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04, 0.04 ])) assert_array_equal(calc_y.growth.factor_adjustment, growth_y.factor_adjustment) assert_array_equal( calc_y.growth._factor_adjustment, np.array([ 0.0, 0.0, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01, 0.01 ]))
def test_full_dropq_puf(puf_path): myvars = {} myvars['_II_rt4'] = [0.39, 0.40, 0.41] myvars['_PT_rt4'] = [0.39, 0.40, 0.41] myvars['_II_rt3'] = [0.31, 0.32, 0.33] myvars['_PT_rt3'] = [0.31, 0.32, 0.33] first = 2016 user_mods = {first: myvars} nyrs = 2 # Create a Policy object (clp) containing current-law policy parameters clp = Policy() clp.implement_reform(user_mods) # Create a Records object (rec) containing all puf.csv input records rec = Records(data=puf_path) # Create a Calculator object using clp policy and puf records calc = Calculator(policy=clp, records=rec) calc.increment_year() calc.increment_year() calc.increment_year() # Create aggregate diagnostic table (adt) as a Pandas DataFrame object adt = multiyear_diagnostic_table(calc, nyrs) taxes_fullsample = adt.loc["Combined Liability ($b)"] assert taxes_fullsample is not None # Create a Public Use File object tax_data = pd.read_csv(puf_path) (mY_dec, _, _, _, _, _, _, _, _, _, fiscal_tots) = dropq.run_models(tax_data, start_year=first, user_mods=user_mods, return_json=False, num_years=nyrs) pure_reform_revenue = taxes_fullsample.loc[first] dropq_reform_revenue = mY_dec['_combined_dec_0'].loc['sums'] dropq_reform_revenue *= 1e-9 # convert to billions of dollars diff = abs(pure_reform_revenue - dropq_reform_revenue) # Assert that dropq revenue is similar to the "pure" calculation assert diff / pure_reform_revenue < 0.01 # Assert that Reform - Baseline = Reported Delta delta_yr0 = fiscal_tots[0] baseline_yr0 = fiscal_tots[1] reform_yr0 = fiscal_tots[2] diff_yr0 = (reform_yr0.loc['combined_tax'] - baseline_yr0.loc['combined_tax']).values delta_yr0 = delta_yr0.loc['combined_tax'].values npt.assert_allclose(diff_yr0, delta_yr0)
def test_with_pufcsv(puf_fullsample): # specify usermods dictionary in code start_year = 2017 reform_year = start_year analysis_year = 2026 year_n = analysis_year - start_year reform = {'_FICA_ss_trt': [0.2]} usermods = dict() usermods['policy'] = {reform_year: reform} usermods['consumption'] = {} usermods['behavior'] = {} usermods['growdiff_baseline'] = {} usermods['growdiff_response'] = {} usermods['gdp_elasticity'] = {} seed = random_seed(usermods) assert seed == 1574318062 # create a Policy object (pol) containing reform policy parameters pol = Policy() pol.implement_reform(usermods['policy']) # create a Records object (rec) containing all puf.csv input records rec = Records(data=puf_fullsample) # create a Calculator object using clp policy and puf records calc = Calculator(policy=pol, records=rec) while calc.current_year < analysis_year: calc.increment_year() # create aggregate diagnostic table (adt) as a Pandas DataFrame object adt = multiyear_diagnostic_table(calc, 1) taxes_fullsample = adt.loc["Combined Liability ($b)"] assert taxes_fullsample is not None fulls_reform_revenue = float(taxes_fullsample.loc[analysis_year]) # create a Public Use File object tax_data = puf_fullsample # call run_nth_year_tax_calc_model function resdict = run_nth_year_tax_calc_model(year_n, start_year, tax_data, usermods, return_json=True) total = resdict['aggr_2'] dropq_reform_revenue = float(total['combined_tax_9']) * 1e-9 # assert that dropq revenue is similar to the fullsample calculation diff = abs(fulls_reform_revenue - dropq_reform_revenue) proportional_diff = diff / fulls_reform_revenue frmt = 'f,d,adiff,pdiff= {:.4f} {:.4f} {:.4f} {}' print( frmt.format(fulls_reform_revenue, dropq_reform_revenue, diff, proportional_diff)) assert proportional_diff < 0.0001 # one-hundredth of one percent