def test_make_Calculator_with_multiyear_reform(): # create a Policy object and apply a policy reform policy3 = Policy() reform3 = {2015: {}} reform3[2015]['_STD_Aged'] = [[1600, 1300, 1600, 1300, 1600, 1300]] reform3[2015]['_II_em'] = [5000, 6000] # reform values for 2015 and 2016 reform3[2015]['_II_em_cpi'] = False policy3.implement_reform(reform3) # create a Calculator object using this policy-reform puf = Records(data=TAXDATA, weights=WEIGHTS, start_year=2009) calc3 = Calculator(policy=policy3, records=puf) # check that Policy object embedded in Calculator object is correct assert calc3.current_year == 2013 assert calc3.policy.II_em == 3900 assert calc3.policy.num_years == Policy.DEFAULT_NUM_YEARS exp_II_em = [3900, 3950, 5000] + [6000] * (Policy.DEFAULT_NUM_YEARS - 3) assert_allclose(calc3.policy._II_em, np.array(exp_II_em), atol=0.01, rtol=0.0) calc3.increment_year() calc3.increment_year() assert calc3.current_year == 2015 assert_allclose(calc3.policy.STD_Aged, np.array([1600, 1300, 1600, 1300, 1600, 1300]), atol=0.01, rtol=0.0)
def test_puf_var_stats(tests_path, puf_fullsample): """ Main logic of test. """ # create a Calculator object rec = Records(data=puf_fullsample) calc = Calculator(policy=Policy(), records=rec, verbose=False) # create base tables table_mean = create_base_table(tests_path) table_corr = copy.deepcopy(table_mean) # 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.to_csv(mean_path, header=year_headers, float_format='%8.3f') corr_path = os.path.join(tests_path, CORR_FILENAME + '-new') table_corr.to_csv(corr_path, float_format='%8.3f') # compare new and old CSV files diffs_in_mean, mean_msg = differences(mean_path, mean_path[:-4], 'MEAN') diffs_in_corr, corr_msg = differences(corr_path, corr_path[:-4], 'CORR') if diffs_in_mean or diffs_in_corr: raise ValueError(mean_msg + corr_msg)
def test_make_Calculator_with_reform_after_start_year(): # create Policy object using custom indexing rates irates = {2013: 0.01, 2014: 0.01, 2015: 0.02, 2016: 0.01, 2017: 0.03} parm = Policy(start_year=2013, num_years=len(irates), inflation_rates=irates) # specify reform in 2015, which is two years after Policy start_year reform = {2015: {}, 2016: {}} reform[2015]['_STD_Aged'] = [[1600, 1300, 1600, 1300, 1600, 1300]] reform[2015]['_II_em'] = [5000] reform[2016]['_II_em'] = [6000] reform[2016]['_II_em_cpi'] = False parm.implement_reform(reform) recs = Records(data=TAX_DTA, weights=WEIGHTS, start_year=2009) calc = Calculator(policy=parm, records=recs) # compare actual and expected parameter values over all years exp_STD_Aged = np.array([[1500, 1200, 1200, 1500, 1500, 1200], [1550, 1200, 1200, 1550, 1550, 1200], [1600, 1300, 1600, 1300, 1600, 1300], [1632, 1326, 1632, 1326, 1632, 1326], [1648, 1339, 1648, 1339, 1648, 1339]]) exp_II_em = np.array([3900, 3950, 5000, 6000, 6000]) assert_array_equal(calc.policy._STD_Aged, exp_STD_Aged) assert_array_equal(calc.policy._II_em, exp_II_em) # compare actual and expected values for 2015 calc.increment_year() calc.increment_year() assert calc.current_year == 2015 exp_2015_II_em = 5000 assert_array_equal(calc.policy.II_em, exp_2015_II_em) exp_2015_STD_Aged = np.array([1600, 1300, 1600, 1300, 1600, 1300]) assert_array_equal(calc.policy.STD_Aged, exp_2015_STD_Aged)
def test_proportional_change_in_gdp(cps_subsample): """ Test correct and incorrect calls to proportional_change_in_gdp function. """ rec = Records.cps_constructor(data=cps_subsample, no_benefits=True) pol = Policy() calc1 = Calculator(policy=pol, records=rec) reform = {2015: {'_II_em': [0.0]}} # reform increases taxes and MTRs pol.implement_reform(reform) calc2 = Calculator(policy=pol, records=rec) assert calc1.current_year == calc2.current_year assert calc1.current_year == 2014 # because using CPS data gdpc = proportional_change_in_gdp(2014, calc1, calc2, elasticity=0.36) assert gdpc == 0.0 # no effect for first data year gdpc = proportional_change_in_gdp(2015, calc1, calc2, elasticity=0.36) assert gdpc == 0.0 # no effect in first year of reform calc1.increment_year() calc2.increment_year() assert calc1.current_year == 2015 gdp_pchg = 100.0 * proportional_change_in_gdp( 2016, calc1, calc2, elasticity=0.36) exp_pchg = -0.54 # higher MTRs imply negative expected GDP percent change abs_diff_pchg = abs(gdp_pchg - exp_pchg) if abs_diff_pchg > 0.01: msg = 'year,gdp_pchg,exp_pchg= {} {:.3f} {:.3f}'.format( 2016, gdp_pchg, exp_pchg) assert msg == 'ERROR: gdp_pchg not close to exp_pchg' # skip calcN.increment_year to 2016, so calcN.current_year is still 2015 with pytest.raises(ValueError): proportional_change_in_gdp(2017, calc1, calc2, elasticity=0.36)
def test_make_Calculator_with_reform_after_start_year(): # create Policy object using custom indexing rates irates = {2013: 0.01, 2014: 0.01, 2015: 0.02, 2016: 0.01, 2017: 0.03} parm = Policy(start_year=2013, num_years=len(irates), inflation_rates=irates) # specify reform in 2015, which is two years after Policy start_year reform = {2015: {}, 2016: {}} reform[2015]['_STD_Aged'] = [[1600, 1300, 1600, 1300, 1600, 1300]] reform[2015]['_II_em'] = [5000] reform[2016]['_II_em'] = [6000] reform[2016]['_II_em_cpi'] = False parm.implement_reform(reform) recs = Records(data=TAXDATA, weights=WEIGHTS, start_year=2009) calc = Calculator(policy=parm, records=recs) # compare actual and expected parameter values over all years exp_STD_Aged = np.array([[1500, 1200, 1200, 1500, 1500, 1200], [1550, 1200, 1200, 1550, 1550, 1200], [1600, 1300, 1600, 1300, 1600, 1300], [1632, 1326, 1632, 1326, 1632, 1326], [1648, 1339, 1648, 1339, 1648, 1339]]) exp_II_em = np.array([3900, 3950, 5000, 6000, 6000]) assert_allclose(calc.policy._STD_Aged, exp_STD_Aged, atol=0.5, rtol=0.0) assert_allclose(calc.policy._II_em, exp_II_em, atol=0.001, rtol=0.0) # compare actual and expected values for 2015 calc.increment_year() calc.increment_year() assert calc.current_year == 2015 exp_2015_II_em = 5000 assert_allclose(calc.policy.II_em, exp_2015_II_em, atol=0.0, rtol=0.0) exp_2015_STD_Aged = np.array([1600, 1300, 1600, 1300, 1600, 1300]) assert_allclose(calc.policy.STD_Aged, exp_2015_STD_Aged, atol=0.0, rtol=0.0)
def test_make_calculator_with_multiyear_reform(cps_subsample): """ Test Calculator class ctor with multi-year policy reform. """ rec = Records.cps_constructor(data=cps_subsample) year = rec.current_year # create a Policy object and apply a policy reform pol = Policy() reform = { 'II_em': { 2015: 5000, 2016: 6000 }, 'II_em-indexed': { 2015: False }, 'STD_Aged': { 2016: [1600, 1300, 1600, 1300, 1600] } } pol.implement_reform(reform) # create a Calculator object using this policy-reform calc = Calculator(policy=pol, records=rec) # check that Policy object embedded in Calculator object is correct assert pol.num_years == Policy.DEFAULT_NUM_YEARS assert calc.current_year == year assert calc.policy_param('II_em') == 3950 exp_II_em = [3900, 3950, 5000] + [6000] * (Policy.DEFAULT_NUM_YEARS - 3) assert np.allclose(calc.policy_param('_II_em'), np.array(exp_II_em)) calc.increment_year() calc.increment_year() assert calc.current_year == 2016 assert np.allclose(calc.policy_param('STD_Aged'), np.array([1600, 1300, 1600, 1300, 1600]))
def test_make_Calculator_with_reform_after_start_year(records_2009): # create Policy object using custom indexing rates irates = {2013: 0.01, 2014: 0.01, 2015: 0.02, 2016: 0.01, 2017: 0.03} parm = Policy(start_year=2013, num_years=len(irates), inflation_rates=irates) # specify reform in 2015, which is two years after Policy start_year reform = {2015: {}, 2016: {}} reform[2015]['_STD_Aged'] = [[1600, 1300, 1600, 1300, 1600, 1300]] reform[2015]['_II_em'] = [5000] reform[2016]['_II_em'] = [6000] reform[2016]['_II_em_cpi'] = False parm.implement_reform(reform) calc = Calculator(policy=parm, records=records_2009) # compare actual and expected parameter values over all years assert np.allclose(calc.policy._STD_Aged, np.array([[1500, 1200, 1200, 1500, 1500, 1200], [1550, 1200, 1200, 1550, 1550, 1200], [1600, 1300, 1600, 1300, 1600, 1300], [1632, 1326, 1632, 1326, 1632, 1326], [1648, 1339, 1648, 1339, 1648, 1339]]), atol=0.5, rtol=0.0) # handles rounding to dollars assert np.allclose(calc.policy._II_em, np.array([3900, 3950, 5000, 6000, 6000])) # compare actual and expected values for 2015 calc.increment_year() calc.increment_year() assert calc.current_year == 2015 assert np.allclose(calc.policy.II_em, 5000) assert np.allclose(calc.policy.STD_Aged, np.array([1600, 1300, 1600, 1300, 1600, 1300]))
def taxcalc_results(start_year, reform_dict, itax_clp, ptax_clp): """ Use taxcalc package on this computer to compute aggregate income tax and payroll tax revenue difference (between reform and current-law policy) for ten years beginning with the specified start_year using the specified reform_dict dictionary and the two specified current-law-policy results dictionaries. Return two aggregate tax revenue difference dictionaries indexed by calendar year. """ pol = Policy() pol.implement_reform(reform_dict) calc = Calculator(policy=pol, records=Records(data=PUF_PATH), verbose=False) calc.advance_to_year(start_year) nyears = NUMBER_OF_YEARS adts = list() for iyr in range(-1, nyears - 1): calc.calc_all() adts.append(create_diagnostic_table(calc)) if iyr < nyears: calc.increment_year() adt = pd.concat(adts, axis=1) # note that adt is Pandas DataFrame object itax_ref = adt.xs('Ind Income Tax ($b)').to_dict() ptax_ref = adt.xs('Payroll Taxes ($b)').to_dict() itax_diff = {} ptax_diff = {} for year in itax_ref: itax_diff[year] = round(itax_ref[year] - itax_clp[year], 1) ptax_diff[year] = round(ptax_ref[year] - ptax_clp[year], 1) return (itax_diff, ptax_diff)
def test_make_Calculator_with_reform_after_start_year(records_2009): # create Policy object using custom indexing rates irates = {2013: 0.01, 2014: 0.01, 2015: 0.02, 2016: 0.01, 2017: 0.03} parm = Policy(start_year=2013, num_years=len(irates), inflation_rates=irates) # specify reform in 2015, which is two years after Policy start_year reform = {2015: {}, 2016: {}} reform[2015]['_STD_Aged'] = [[1600, 1300, 1600, 1300, 1600, 1300]] reform[2015]['_II_em'] = [5000] reform[2016]['_II_em'] = [6000] reform[2016]['_II_em_cpi'] = False parm.implement_reform(reform) calc = Calculator(policy=parm, records=records_2009) # compare actual and expected parameter values over all years assert np.allclose(calc.policy._STD_Aged, np.array([[1500, 1200, 1200, 1500, 1500, 1200], [1550, 1200, 1200, 1550, 1550, 1200], [1600, 1300, 1600, 1300, 1600, 1300], [1632, 1326, 1632, 1326, 1632, 1326], [1648, 1339, 1648, 1339, 1648, 1339]]), atol=0.5, rtol=0.0) # handles rounding to dollars assert np.allclose(calc.policy._II_em, np.array([3900, 3950, 5000, 6000, 6000])) # compare actual and expected values for 2015 calc.increment_year() calc.increment_year() assert calc.current_year == 2015 assert np.allclose(calc.policy.II_em, 5000) assert np.allclose(calc.policy.STD_Aged, np.array([1600, 1300, 1600, 1300, 1600, 1300]))
def test_make_calculator_with_multiyear_reform(cps_subsample): """ Test Calculator class ctor with multi-year policy reform. """ rec = Records.cps_constructor(data=cps_subsample) year = rec.current_year # create a Policy object and apply a policy reform pol = Policy() reform = {2015: {}, 2016: {}} reform[2015]['_II_em'] = [5000, 6000] # reform values for 2015 and 2016 reform[2015]['_II_em_cpi'] = False reform[2016]['_STD_Aged'] = [[1600, 1300, 1600, 1300, 1600]] pol.implement_reform(reform) # create a Calculator object using this policy-reform calc = Calculator(policy=pol, records=rec) # check that Policy object embedded in Calculator object is correct assert pol.num_years == Policy.DEFAULT_NUM_YEARS assert calc.current_year == year assert calc.policy_param('II_em') == 3950 exp_II_em = [3900, 3950, 5000] + [6000] * (Policy.DEFAULT_NUM_YEARS - 3) assert np.allclose(calc.policy_param('_II_em'), np.array(exp_II_em)) calc.increment_year() calc.increment_year() assert calc.current_year == 2016 assert np.allclose(calc.policy_param('STD_Aged'), np.array([1600, 1300, 1600, 1300, 1600]))
def get_calculator(baseline, calculator_start_year, reform=None, data='cps', weights=None, records_start_year=RECORDS_START_YEAR): ''' This function creates the tax calculator object for the microsim Args: baseline: boolean, True if baseline tax policy calculator_start_year: integer, first year of budget window reform: dictionary, reform parameters data: DataFrame, DataFrame for Records object (opt.) weights: DataFrame, weights DataFrame for Records object (opt.) records_start_year: integer, the start year for the data and weights dfs Returns: calc1: Tax Calculator Calculator object with a current_year equal to calculator_start_year ''' # create a calculator policy1 = Policy() if data is not None and "cps" in data: records1 = Records.cps_constructor() # impute short and long term capital gains if using CPS data # in 2012 SOI data 6.587% of CG as short-term gains records1.p22250 = 0.06587 * records1.e01100 records1.p23250 = (1 - 0.06587) * records1.e01100 # set total capital gains to zero records1.e01100 = np.zeros(records1.e01100.shape[0]) elif data is not None: records1 = Records(data=data, weights=weights, start_year=records_start_year) else: records1 = Records() if baseline: # Should not be a reform if baseline is True assert not reform if not baseline: policy1.implement_reform(reform) # the default set up increments year to 2013 calc1 = Calculator(records=records1, policy=policy1) # this increment_year function extrapolates all PUF variables to # the next year so this step takes the calculator to the start_year if calculator_start_year > TC_LAST_YEAR: raise RuntimeError("Start year is beyond data extrapolation.") while calc1.current_year < calculator_start_year: calc1.increment_year() return calc1
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 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_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, mX_dec, df_dec, pdf_dec, cdf_dec, mY_bin, mX_bin, df_bin, pdf_bin, cdf_bin, fiscal_tots) = dropq.run_models(tax_data, start_year=first, user_mods=user_mods, return_json=False, num_years=2) pure_reform_revenue = taxes_fullsample.loc[first] dropq_reform_revenue = mY_dec['_combined_dec_0'].loc['sums'] dropq_reform_revenue /= 1e9 # Round to billions of dollars diff = abs(pure_reform_revenue - dropq_reform_revenue) # Assert that dropq revenue is similar to the "pure" calculation assert diff / dropq_reform_revenue < 0.02 # 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_array_almost_equal(diff_yr0, delta_yr0, decimal=3)
def test_create_tables(puf_1991, weights_1991): # create a current-law Policy object and Calculator object calc1 policy1 = Policy() records1 = Records(data=puf_1991, weights=weights_1991, 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=puf_1991, weights=weights_1991, start_year=2009) calc2 = Calculator(policy=policy2, records=records2) calc2.calc_all() # test creating various distribution tables dt1 = create_difference_table(calc1.records, calc2.records, groupby='large_income_bins') assert isinstance(dt1, pd.DataFrame) dt2 = create_difference_table(calc1.records, calc2.records, groupby='webapp_income_bins') assert isinstance(dt2, pd.DataFrame) with pytest.raises(ValueError): create_difference_table(calc1.records, calc2.records, groupby='bad_bins') with pytest.raises(ValueError): create_distribution_table(calc2.records, groupby='small_income_bins', result_type='bad_result_type') with pytest.raises(ValueError): create_distribution_table(calc2.records, groupby='bad_bins', result_type='weighted_sum') dt3 = create_distribution_table(calc2.records, groupby='small_income_bins', result_type='weighted_sum', baseline_obj=calc1.records, diffs=True) assert isinstance(dt3, pd.DataFrame) calc1.increment_year() with pytest.raises(ValueError): create_difference_table(calc1.records, calc2.records, groupby='large_income_bins') with pytest.raises(ValueError): create_distribution_table(calc2.records, groupby='small_income_bins', result_type='weighted_sum', baseline_obj=calc1.records, diffs=True)
def reform_results(reform_dict, puf_data): """ Return actual results of the reform specified in reform_dict. """ # pylint: disable=too-many-locals # create current-law-policy Calculator object pol1 = Policy() rec1 = Records(data=puf_data) calc1 = Calculator(policy=pol1, records=rec1, verbose=False, behavior=None) # create reform Calculator object with possible behavioral responses start_year = reform_dict['start_year'] beh2 = 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}} beh2.update_behavior(beh_assump) reform = {start_year: reform_dict['value']} pol2 = Policy() pol2.implement_reform(reform) rec2 = Records(data=puf_data) calc2 = Calculator(policy=pol2, records=rec2, verbose=False, behavior=beh2) # increment both calculators 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 = getattr(calc1.records, output_type) if calc2.behavior.has_response(): calc_clp = calc2.current_law_version() calc2_br = Behavior.response(calc_clp, calc2) postreform = getattr(calc2_br.records, output_type) else: calc2.calc_all() postreform = getattr(calc2.records, output_type) diff = postreform - prereform weighted_sum_diff = (diff * calc1.records.s006).sum() * 1.0e-9 results.append(weighted_sum_diff) calc1.increment_year() calc2.increment_year() # write actual results to actual_str reform_description = reform_dict['name'] actual_str = '{}\n'.format(reform_description) actual_str += 'Tax-Calculator' for iyr in range(0, num_years): actual_str += ',{:.1f}'.format(results[iyr]) return actual_str
def test_factor_adjustment(records_2009): calc = Calculator(policy=Policy(), records=records_2009, growth=Growth()) ATXPY_pre = calc.records.BF.ATXPY[2015] AGDPN_pre = calc.records.BF.AGDPN[2015] # specify _factor_adjustment fa2015 = 0.01 factor_adj = {2015: {'_factor_adjustment': [fa2015]}} calc.growth.update_economic_growth(factor_adj) assert calc.current_year == 2013 calc.increment_year() calc.increment_year() assert calc.current_year == 2015 assert calc.records.BF.AGDPN[2015] == AGDPN_pre + fa2015 assert calc.records.BF.ATXPY[2015] == ATXPY_pre + fa2015
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 test_factor_adjustment(records_2009): calc = Calculator(policy=Policy(), records=records_2009, growth=Growth()) ATXPY_pre = calc.records.BF.ATXPY[2015] AGDPN_pre = calc.records.BF.AGDPN[2015] # specify _factor_adjustment fa2015 = 0.01 factor_adj = {2015: {'_factor_adjustment': [fa2015]}} calc.growth.update_economic_growth(factor_adj) assert calc.current_year == 2013 calc.increment_year() calc.increment_year() assert calc.current_year == 2015 assert calc.records.BF.AGDPN[2015] == AGDPN_pre + fa2015 assert calc.records.BF.ATXPY[2015] == ATXPY_pre + fa2015
def test_factor_adjustment(): recs = Records(data=TAXDATA, weights=WEIGHTS, start_year=2009) calc = Calculator(policy=Policy(), records=recs, growth=Growth()) ATXPY_pre = calc.records.BF.ATXPY[2015] AGDPN_pre = calc.records.BF.AGDPN[2015] # specify _factor_adjustment fa2015 = 0.01 factor_adj = {2015: {'_factor_adjustment': [fa2015]}} calc.growth.update_economic_growth(factor_adj) assert calc.current_year == 2013 calc.increment_year() calc.increment_year() assert calc.current_year == 2015 assert calc.records.BF.AGDPN[2015] == AGDPN_pre + fa2015 assert calc.records.BF.ATXPY[2015] == ATXPY_pre + fa2015
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
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['growdiff_baseline'] = {} usermods['growdiff_response'] = {} seed = random_seed(usermods) assert seed == 2568216296 # 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 = calc.diagnostic_table(1) taxes_fullsample = adt.loc["Combined Liability ($b)"] assert taxes_fullsample is not None fulls_reform_revenue = float(taxes_fullsample.loc[analysis_year]) # call run_nth_year_tax_calc_model function resdict = run_nth_year_taxcalc_model(year_n, start_year, use_puf_not_cps=True, use_full_sample=True, user_mods=usermods, return_dict=True) total = resdict['aggr_2'] tbi_reform_revenue = float(total['combined_tax_9']) # assert that tbi revenue is similar to the fullsample calculation diff = abs(fulls_reform_revenue - tbi_reform_revenue) proportional_diff = diff / fulls_reform_revenue frmt = 'f,d,adiff,pdiff= {:.4f} {:.4f} {:.4f} {}' print(frmt.format(fulls_reform_revenue, tbi_reform_revenue, diff, proportional_diff)) assert proportional_diff < 0.0001 # one-hundredth of one percent
def reform_results(rid, reform_dict, puf_data, reform_2017_law): """ Return actual results of the reform specified by rid and 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'] == 'policy_current_law.json': pass else: msg = 'illegal baseline value {}' raise ValueError(msg.format(reform_dict['baseline'])) calc1 = Calculator(policy=pol, records=rec, verbose=False) # create reform Calculator object, calc2 start_year = reform_dict['start_year'] reform = dict() for name, value in reform_dict['value'].items(): reform[name] = {start_year: value} pol.implement_reform(reform) calc2 = Calculator(policy=pol, records=rec, verbose=False) # increment both Calculator objects to reform's start_year calc1.advance_to_year(start_year) calc2.advance_to_year(start_year) # calculate baseline and reform output for several years output_type = reform_dict['output_type'] num_years = 4 results = list() for _ in range(0, num_years): calc1.calc_all() baseline = calc1.array(output_type) calc2.calc_all() reform = calc2.array(output_type) diff = reform - baseline 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 = '{}'.format(rid) for iyr in range(0, num_years): actual_str += ',{:.1f}'.format(results[iyr]) return actual_str
def reform_results(rid, reform_dict, reform_2017_law): """ Return actual results of the reform specified by rid and reform_dict. """ # pylint: disable=too-many-locals rec = Records.cps_constructor() # create baseline Calculator object, calc1 pol = Policy() if reform_dict['baseline'] == '2017_law.json': pol.implement_reform(reform_2017_law) elif reform_dict['baseline'] == 'policy_current_law.json': pass else: msg = 'illegal baseline value {}' raise ValueError(msg.format(reform_dict['baseline'])) calc1 = Calculator(policy=pol, records=rec, verbose=False) # create reform Calculator object, calc2 start_year = reform_dict['start_year'] reform = dict() for name, value in reform_dict['value'].items(): reform[name] = {start_year: value} pol.implement_reform(reform) calc2 = Calculator(policy=pol, records=rec, verbose=False) # increment both Calculator objects to reform's start_year calc1.advance_to_year(start_year) calc2.advance_to_year(start_year) # calculate baseline and reform output for several years output_type = reform_dict['output_type'] num_years = 4 results = list() for _ in range(0, num_years): calc1.calc_all() baseline = calc1.array(output_type) calc2.calc_all() reform = calc2.array(output_type) diff = reform - baseline 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 = '{}'.format(rid) for iyr in range(0, num_years): actual_str += ',{:.1f}'.format(results[iyr]) return actual_str
def test_factor_target(records_2009): calc = Calculator(policy=Policy(), records=records_2009, growth=Growth()) AGDPN_pre = calc.records.BF.AGDPN[2015] ATXPY_pre = calc.records.BF.ATXPY[2015] # specify _factor_target ft2015 = 0.04 factor_target = {2015: {'_factor_target': [ft2015]}} calc.growth.update_economic_growth(factor_target) assert calc.current_year == 2013 calc.increment_year() calc.increment_year() assert calc.current_year == 2015 distance = ((ft2015 - Growth.default_real_gdp_growth_rate(2015 - 2013)) / calc.records.BF.APOPN[2015]) AGDPN_post = AGDPN_pre + distance ATXPY_post = ATXPY_pre + distance assert calc.records.BF.AGDPN[2015] == AGDPN_post assert calc.records.BF.ATXPY[2015] == ATXPY_post
def test_factor_target(records_2009): calc = Calculator(policy=Policy(), records=records_2009, growth=Growth()) AGDPN_pre = calc.records.BF.AGDPN[2015] ATXPY_pre = calc.records.BF.ATXPY[2015] # specify _factor_target ft2015 = 0.04 factor_target = {2015: {'_factor_target': [ft2015]}} calc.growth.update_economic_growth(factor_target) assert calc.current_year == 2013 calc.increment_year() calc.increment_year() assert calc.current_year == 2015 distance = ((ft2015 - Growth.default_real_gdp_growth_rate(2015 - 2013)) / calc.records.BF.APOPN[2015]) AGDPN_post = AGDPN_pre + distance ATXPY_post = ATXPY_pre + distance assert calc.records.BF.AGDPN[2015] == AGDPN_post assert calc.records.BF.ATXPY[2015] == ATXPY_post
def test_create_tables(puf_1991, weights_1991): # create a current-law Policy object and Calculator object calc1 policy1 = Policy() records1 = Records(data=puf_1991, weights=weights_1991, 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=puf_1991, weights=weights_1991, start_year=2009) calc2 = Calculator(policy=policy2, records=records2) calc2.calc_all() # test creating various distribution tables dt1 = create_difference_table(calc1.records, calc2.records, groupby='large_income_bins') dt2 = create_difference_table(calc1.records, calc2.records, groupby='webapp_income_bins') with pytest.raises(ValueError): dt = create_difference_table(calc1.records, calc2.records, groupby='bad_bins') with pytest.raises(ValueError): dt = create_distribution_table(calc2.records, groupby='small_income_bins', result_type='bad_result_type') with pytest.raises(ValueError): dt = create_distribution_table(calc2.records, groupby='bad_bins', result_type='weighted_sum') dt3 = create_distribution_table(calc2.records, groupby='small_income_bins', result_type='weighted_sum', baseline_obj=calc1.records, diffs=True) calc1.increment_year() with pytest.raises(ValueError): dt = create_difference_table(calc1.records, calc2.records, groupby='large_income_bins') with pytest.raises(ValueError): dt = create_distribution_table(calc2.records, groupby='small_income_bins', result_type='weighted_sum', baseline_obj=calc1.records, diffs=True)
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), verbose=False) nyears = MAX_START_YEAR + NUMBER_OF_YEARS - MIN_START_YEAR - 1 adts = list() for iyr in range(-1, nyears - 1): calc.calc_all() adts.append(create_diagnostic_table(calc)) if iyr < nyears: calc.increment_year() adt = pd.concat(adts, axis=1) # note that adt is Pandas DataFrame object return (adt.xs('Ind Income Tax ($b)').to_dict(), adt.xs('Payroll Taxes ($b)').to_dict())
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.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 mean_msg = differences(mean_path, mean_path[:-4], 'MEAN') corr_msg = differences(corr_path, corr_path[:-4], 'CORR') if mean_msg or corr_msg: raise ValueError(mean_msg + corr_msg)
def test_make_Calculator_with_multiyear_reform(): # create a Policy object and apply a policy reform policy3 = Policy() reform3 = {2015: {}} reform3[2015]['_STD_Aged'] = [[1600, 1300, 1600, 1300, 1600, 1300]] reform3[2015]['_II_em'] = [5000, 6000] # reform values for 2015 and 2016 reform3[2015]['_II_em_cpi'] = False policy3.implement_reform(reform3) # create a Calculator object using this policy-reform puf = Records(data=TAX_DTA, weights=WEIGHTS, start_year=2009) calc3 = Calculator(policy=policy3, records=puf) # check that Policy object embedded in Calculator object is correct assert calc3.current_year == 2013 assert calc3.policy.II_em == 3900 assert calc3.policy.num_years == 12 exp_II_em = [3900, 3950, 5000] + [6000] * 9 assert_array_equal(calc3.policy._II_em, np.array(exp_II_em)) calc3.increment_year() calc3.increment_year() assert calc3.current_year == 2015 assert_array_equal(calc3.policy.STD_Aged, np.array([1600, 1300, 1600, 1300, 1600, 1300]))
def test_make_Calculator_with_multiyear_reform(records_2009): # create a Policy object and apply a policy reform policy3 = Policy() reform3 = {2015: {}} reform3[2015]['_STD_Aged'] = [[1600, 1300, 1600, 1300, 1600, 1300]] reform3[2015]['_II_em'] = [5000, 6000] # reform values for 2015 and 2016 reform3[2015]['_II_em_cpi'] = False policy3.implement_reform(reform3) # create a Calculator object using this policy-reform calc3 = Calculator(policy=policy3, records=records_2009) # check that Policy object embedded in Calculator object is correct assert calc3.current_year == 2013 assert calc3.policy.II_em == 3900 assert calc3.policy.num_years == Policy.DEFAULT_NUM_YEARS exp_II_em = [3900, 3950, 5000] + [6000] * (Policy.DEFAULT_NUM_YEARS - 3) assert np.allclose(calc3.policy._II_em, np.array(exp_II_em)) calc3.increment_year() calc3.increment_year() assert calc3.current_year == 2015 assert np.allclose(calc3.policy.STD_Aged, np.array([1600, 1300, 1600, 1300, 1600, 1300]))
def test_make_calculator_with_multiyear_reform(cps_subsample): rec = Records.cps_constructor(data=cps_subsample) year = rec.current_year # create a Policy object and apply a policy reform pol = Policy() reform = {2015: {}, 2016: {}} reform[2015]['_II_em'] = [5000, 6000] # reform values for 2015 and 2016 reform[2015]['_II_em_cpi'] = False reform[2016]['_STD_Aged'] = [[1600, 1300, 1600, 1300, 1600]] pol.implement_reform(reform) # create a Calculator object using this policy-reform calc = Calculator(policy=pol, records=rec) # check that Policy object embedded in Calculator object is correct assert calc.current_year == year assert calc.policy.II_em == 3950 assert calc.policy.num_years == Policy.DEFAULT_NUM_YEARS exp_II_em = [3900, 3950, 5000] + [6000] * (Policy.DEFAULT_NUM_YEARS - 3) assert np.allclose(calc.policy._II_em, np.array(exp_II_em)) calc.increment_year() calc.increment_year() assert calc.current_year == 2016 assert np.allclose(calc.policy.STD_Aged, np.array([1600, 1300, 1600, 1300, 1600]))
def calculator_objects(year_n, start_year, use_puf_not_cps, use_full_sample, user_mods, behavior_allowed): """ This function assumes that the specified user_mods is a dictionary returned by the Calculator.read_json_param_objects() function. This function returns (calc1, calc2) where calc1 is pre-reform Calculator object calculated for year_n, and calc2 is post-reform Calculator object calculated for year_n. Set behavior_allowed to False when generating static results or set behavior_allowed to True when generating dynamic results. """ # pylint: disable=too-many-arguments,too-many-locals # pylint: disable=too-many-branches,too-many-statements check_user_mods(user_mods) # specify Consumption instance consump = Consumption() consump_assumptions = user_mods['consumption'] consump.update_consumption(consump_assumptions) # specify growdiff_baseline and growdiff_response growdiff_baseline = GrowDiff() growdiff_response = GrowDiff() growdiff_base_assumps = user_mods['growdiff_baseline'] growdiff_resp_assumps = user_mods['growdiff_response'] growdiff_baseline.update_growdiff(growdiff_base_assumps) growdiff_response.update_growdiff(growdiff_resp_assumps) # create pre-reform and post-reform GrowFactors instances growfactors_pre = GrowFactors() growdiff_baseline.apply_to(growfactors_pre) growfactors_post = GrowFactors() growdiff_baseline.apply_to(growfactors_post) growdiff_response.apply_to(growfactors_post) # create sample pd.DataFrame from specified input file and sampling scheme tbi_path = os.path.abspath(os.path.dirname(__file__)) if use_puf_not_cps: # first try TaxBrain deployment path input_path = 'puf.csv.gz' if not os.path.isfile(input_path): # otherwise try local Tax-Calculator deployment path input_path = os.path.join(tbi_path, '..', '..', 'puf.csv') sampling_frac = 0.05 sampling_seed = 2222 else: # if using cps input not puf input # first try Tax-Calculator code path input_path = os.path.join(tbi_path, '..', 'cps.csv.gz') if not os.path.isfile(input_path): # otherwise read from taxcalc package "egg" input_path = None # pragma: no cover full_sample = read_egg_csv('cps.csv.gz') # pragma: no cover sampling_frac = 0.03 sampling_seed = 180 if input_path: full_sample = pd.read_csv(input_path) if use_full_sample: sample = full_sample else: sample = full_sample.sample(frac=sampling_frac, random_state=sampling_seed) # create pre-reform Calculator instance if use_puf_not_cps: recs1 = Records(data=sample, gfactors=growfactors_pre) else: recs1 = Records.cps_constructor(data=sample, gfactors=growfactors_pre) policy1 = Policy(gfactors=growfactors_pre) calc1 = Calculator(policy=policy1, records=recs1, consumption=consump) while calc1.current_year < start_year: calc1.increment_year() calc1.calc_all() assert calc1.current_year == start_year # specify Behavior instance behv = Behavior() behavior_assumps = user_mods['behavior'] behv.update_behavior(behavior_assumps) # always prevent both behavioral response and growdiff response if behv.has_any_response() and growdiff_response.has_any_response(): msg = 'BOTH behavior AND growdiff_response HAVE RESPONSE' raise ValueError(msg) # optionally prevent behavioral response if behv.has_any_response() and not behavior_allowed: msg = 'A behavior RESPONSE IS NOT ALLOWED' raise ValueError(msg) # create post-reform Calculator instance if use_puf_not_cps: recs2 = Records(data=sample, gfactors=growfactors_post) else: recs2 = Records.cps_constructor(data=sample, gfactors=growfactors_post) policy2 = Policy(gfactors=growfactors_post) policy_reform = user_mods['policy'] policy2.implement_reform(policy_reform) calc2 = Calculator(policy=policy2, records=recs2, consumption=consump, behavior=behv) while calc2.current_year < start_year: calc2.increment_year() assert calc2.current_year == start_year # delete objects now embedded in calc1 and calc2 del sample del full_sample del consump del growdiff_baseline del growdiff_response del growfactors_pre del growfactors_post del behv del recs1 del recs2 del policy1 del policy2 # increment Calculator objects for year_n years and calculate for _ in range(0, year_n): calc1.increment_year() calc2.increment_year() calc1.calc_all() if calc2.behavior_has_response(): calc2 = Behavior.response(calc1, calc2) else: calc2.calc_all() # return calculated Calculator objects return (calc1, calc2)
def run_nth_year(year_n, start_year, is_strict, tax_dta="", user_mods="", return_json=True): ######################################################################### # Create Calculators and Masks ######################################################################### records = Records(tax_dta.copy(deep=True)) records2 = copy.deepcopy(records) records3 = copy.deepcopy(records) # add 1 dollar to gross income records2.e00200 += 1 # Default Plans # Create a default Policy object params = Policy(start_year=2013) # Create a Calculator calc1 = Calculator(policy=params, records=records) if is_strict: unknown_params = get_unknown_parameters(user_mods, start_year) if unknown_params: raise ValueError("Unknown parameters: {}".format(unknown_params)) growth_assumptions = only_growth_assumptions(user_mods, start_year) if growth_assumptions: calc1.growth.update_economic_growth(growth_assumptions) while calc1.current_year < start_year: calc1.increment_year() calc1.calc_all() assert calc1.current_year == start_year params2 = Policy(start_year=2013) # Create a Calculator with one extra dollar of income calc2 = Calculator(policy=params2, records=records2) if growth_assumptions: calc2.growth.update_economic_growth(growth_assumptions) while calc2.current_year < start_year: calc2.increment_year() calc2.calc_all() assert calc2.current_year == start_year # where do the results differ.. soit1 = results(calc1) soit2 = results(calc2) mask = (soit1._iitax != soit2._iitax) # User specified Plans behavior_assumptions = only_behavior_assumptions(user_mods, start_year) reform_mods = only_reform_mods(user_mods, start_year) params3 = Policy(start_year=2013) params3.implement_reform(reform_mods) behavior3 = Behavior(start_year=2013) # Create a Calculator for the user specified plan calc3 = Calculator(policy=params3, records=records3, behavior=behavior3) if growth_assumptions: calc3.growth.update_economic_growth(growth_assumptions) if behavior_assumptions: calc3.behavior.update_behavior(behavior_assumptions) while calc3.current_year < start_year: calc3.increment_year() assert calc3.current_year == start_year calc3.calc_all() # Get a random seed based on user specified plan seed = random_seed_from_plan(calc3) np.random.seed(seed) start_time = time.time() for i in range(0, year_n): calc1.increment_year() calc3.increment_year() calc1.calc_all() if calc3.behavior.has_response(): calc3 = Behavior.response(calc1, calc3) else: calc3.calc_all() soit1 = results(calc1) soit3 = results(calc3) # Means of plan Y by decile # diffs of plan Y by decile # Means of plan Y by income bin # diffs of plan Y by income bin mY_dec, mX_dec, df_dec, pdf_dec, cdf_dec, mY_bin, mX_bin, df_bin, \ pdf_bin, cdf_bin, diff_sum, payrolltax_diff_sum, combined_diff_sum = \ groupby_means_and_comparisons(soit1, soit3, mask) elapsed_time = time.time() - start_time print("elapsed time for this run: ", elapsed_time) start_year += 1 #num_fiscal_year_total = format_print(diff_sum) #fica_fiscal_year_total = format_print(payrolltax_diff_sum) #combined_fiscal_year_total = format_print(combined_diff_sum) tots = [diff_sum, payrolltax_diff_sum, combined_diff_sum] fiscal_tots= pd.DataFrame(data=tots, index=total_row_names) # Get rid of negative incomes df_bin.drop(df_bin.index[0], inplace=True) pdf_bin.drop(pdf_bin.index[0], inplace=True) cdf_bin.drop(cdf_bin.index[0], inplace=True) mY_bin.drop(mY_bin.index[0], inplace=True) mX_bin.drop(mX_bin.index[0], inplace=True) if not return_json: return (mY_dec, mX_dec, df_dec, pdf_dec, cdf_dec, mY_bin, mX_bin, df_bin, pdf_bin, cdf_bin, fiscal_tots) decile_row_names_i = [x+'_'+str(year_n) for x in decile_row_names] bin_row_names_i = [x+'_'+str(year_n) for x in bin_row_names] total_row_names_i = [x+'_'+str(year_n) for x in total_row_names] mY_dec_table_i = create_json_table(mY_dec, row_names=decile_row_names_i, column_types=planY_column_types) mX_dec_table_i = create_json_table(mX_dec, row_names=decile_row_names_i, column_types=planY_column_types) df_dec_table_i = create_json_table(df_dec, row_names=decile_row_names_i, column_types=diff_column_types) pdf_dec_table_i = create_json_table(pdf_dec, row_names=decile_row_names_i, column_types=diff_column_types) cdf_dec_table_i = create_json_table(cdf_dec, row_names=decile_row_names_i, column_types=diff_column_types) mY_bin_table_i = create_json_table(mY_bin, row_names=bin_row_names_i, column_types=planY_column_types) mX_bin_table_i = create_json_table(mX_bin, row_names=bin_row_names_i, column_types=planY_column_types) df_bin_table_i = create_json_table(df_bin, row_names=bin_row_names_i, column_types=diff_column_types) pdf_bin_table_i = create_json_table(pdf_bin, row_names=bin_row_names_i, column_types=diff_column_types) cdf_bin_table_i = create_json_table(cdf_bin, row_names=bin_row_names_i, column_types=diff_column_types) fiscal_yr_total = create_json_table(fiscal_tots, row_names=total_row_names_i) # Make the one-item lists of strings just strings fiscal_yr_total = dict((k, v[0]) for k,v in fiscal_yr_total.items()) return (mY_dec_table_i, mX_dec_table_i, df_dec_table_i, pdf_dec_table_i, cdf_dec_table_i, mY_bin_table_i, mX_bin_table_i, df_bin_table_i, pdf_bin_table_i, cdf_bin_table_i, fiscal_yr_total)
def calculate(year_n, start_year, use_puf_not_cps, use_full_sample, user_mods, behavior_allowed): """ The calculate function assumes the specified user_mods is a dictionary returned by the Calculator.read_json_param_objects() function. The function returns (calc1, calc2, mask) where calc1 is pre-reform Calculator object calculated for year_n, calc2 is post-reform Calculator object calculated for year_n, and mask is boolean array marking records with reform-induced iitax diffs Set behavior_allowed to False when generating static results or set behavior_allowed to True when generating dynamic results. """ # pylint: disable=too-many-arguments,too-many-locals # pylint: disable=too-many-branches,too-many-statements check_user_mods(user_mods) # specify Consumption instance consump = Consumption() consump_assumptions = user_mods['consumption'] consump.update_consumption(consump_assumptions) # specify growdiff_baseline and growdiff_response growdiff_baseline = Growdiff() growdiff_response = Growdiff() growdiff_base_assumps = user_mods['growdiff_baseline'] growdiff_resp_assumps = user_mods['growdiff_response'] growdiff_baseline.update_growdiff(growdiff_base_assumps) growdiff_response.update_growdiff(growdiff_resp_assumps) # create pre-reform and post-reform Growfactors instances growfactors_pre = Growfactors() growdiff_baseline.apply_to(growfactors_pre) growfactors_post = Growfactors() growdiff_baseline.apply_to(growfactors_post) growdiff_response.apply_to(growfactors_post) # create sample pd.DataFrame from specified input file and sampling scheme stime = time.time() tbi_path = os.path.abspath(os.path.dirname(__file__)) if use_puf_not_cps: # first try TaxBrain deployment path input_path = 'puf.csv.gz' if not os.path.isfile(input_path): # otherwise try local Tax-Calculator deployment path input_path = os.path.join(tbi_path, '..', '..', 'puf.csv') sampling_frac = 0.05 sampling_seed = 180 else: # if using cps input not puf input # first try Tax-Calculator code path input_path = os.path.join(tbi_path, '..', 'cps.csv.gz') if not os.path.isfile(input_path): # otherwise read from taxcalc package "egg" input_path = None # pragma: no cover full_sample = read_egg_csv('cps.csv.gz') # pragma: no cover sampling_frac = 0.03 sampling_seed = 180 if input_path: full_sample = pd.read_csv(input_path) if use_full_sample: sample = full_sample else: sample = full_sample.sample( # pylint: disable=no-member frac=sampling_frac, random_state=sampling_seed) if use_puf_not_cps: print('puf-read-time= {:.1f}'.format(time.time() - stime)) else: print('cps-read-time= {:.1f}'.format(time.time() - stime)) # create pre-reform Calculator instance if use_puf_not_cps: recs1 = Records(data=copy.deepcopy(sample), gfactors=growfactors_pre) else: recs1 = Records.cps_constructor(data=copy.deepcopy(sample), gfactors=growfactors_pre) policy1 = Policy(gfactors=growfactors_pre) calc1 = Calculator(policy=policy1, records=recs1, consumption=consump) while calc1.current_year < start_year: calc1.increment_year() calc1.calc_all() assert calc1.current_year == start_year # compute mask array res1 = calc1.dataframe(DIST_VARIABLES) if use_puf_not_cps: # create pre-reform Calculator instance with extra income recs1p = Records(data=copy.deepcopy(sample), gfactors=growfactors_pre) # add one dollar to the income of each filing unit to determine # which filing units undergo a resulting change in tax liability recs1p.e00200 += 1.0 # pylint: disable=no-member recs1p.e00200p += 1.0 # pylint: disable=no-member policy1p = Policy(gfactors=growfactors_pre) # create Calculator with recs1p and calculate for start_year calc1p = Calculator(policy=policy1p, records=recs1p, consumption=consump) while calc1p.current_year < start_year: calc1p.increment_year() calc1p.calc_all() assert calc1p.current_year == start_year # compute mask showing which of the calc1 and calc1p results differ; # mask is true if a filing unit's income tax liability changed after # a dollar was added to the filing unit's wage and salary income res1p = calc1p.dataframe(DIST_VARIABLES) mask = np.logical_not( # pylint: disable=no-member np.isclose(res1.iitax, res1p.iitax, atol=0.001, rtol=0.0)) assert np.any(mask) else: # if use_cps_not_cps is False # indicate that no fuzzing of reform results is required mask = np.zeros(res1.shape[0], dtype=np.int8) # specify Behavior instance behv = Behavior() behavior_assumps = user_mods['behavior'] behv.update_behavior(behavior_assumps) # always prevent both behavioral response and growdiff response if behv.has_any_response() and growdiff_response.has_any_response(): msg = 'BOTH behavior AND growdiff_response HAVE RESPONSE' raise ValueError(msg) # optionally prevent behavioral response if behv.has_any_response() and not behavior_allowed: msg = 'A behavior RESPONSE IS NOT ALLOWED' raise ValueError(msg) # create post-reform Calculator instance if use_puf_not_cps: recs2 = Records(data=copy.deepcopy(sample), gfactors=growfactors_post) else: recs2 = Records.cps_constructor(data=copy.deepcopy(sample), gfactors=growfactors_post) policy2 = Policy(gfactors=growfactors_post) policy_reform = user_mods['policy'] policy2.implement_reform(policy_reform) calc2 = Calculator(policy=policy2, records=recs2, consumption=consump, behavior=behv) while calc2.current_year < start_year: calc2.increment_year() calc2.calc_all() assert calc2.current_year == start_year # increment Calculator objects for year_n years and calculate for _ in range(0, year_n): calc1.increment_year() calc2.increment_year() calc1.calc_all() if calc2.behavior_has_response(): calc2 = Behavior.response(calc1, calc2) else: calc2.calc_all() # return calculated Calculator objects and mask return (calc1, calc2, mask)
def run_nth_year_gdp_elast_model(year_n, start_year, taxrec_df, user_mods, return_json=True): """ The run_nth_year_gdp_elast_model function assumes user_mods is a dictionary returned by the Calculator.read_json_parameter_files() function with an extra key:value pair that is specified as 'gdp_elasticity': {'value': <float_value>}. """ # pylint: disable=too-many-arguments,too-many-locals,too-many-statements check_user_mods(user_mods) # Only makes sense to run for budget years 1 through n-1 (not for year 0) assert year_n > 0 # Specify value of gdp_elasticity gdp_elasticity = user_mods['gdp_elasticity']['value'] # Specify Consumption instance consump = Consumption() consump_assumps = user_mods['consumption'] consump.update_consumption(consump_assumps) # Specify growdiff_baseline and growdiff_response growdiff_baseline = Growdiff() growdiff_response = Growdiff() growdiff_base_assumps = user_mods['growdiff_baseline'] growdiff_resp_assumps = user_mods['growdiff_response'] growdiff_baseline.update_growdiff(growdiff_base_assumps) growdiff_response.update_growdiff(growdiff_resp_assumps) # Create pre-reform and post-reform Growfactors instances growfactors_pre = Growfactors() growdiff_baseline.apply_to(growfactors_pre) growfactors_post = Growfactors() growdiff_baseline.apply_to(growfactors_post) growdiff_response.apply_to(growfactors_post) # Create pre-reform Calculator instance records1 = Records(data=taxrec_df.copy(deep=True), gfactors=growfactors_pre) policy1 = Policy(gfactors=growfactors_pre) calc1 = Calculator(policy=policy1, records=records1, consumption=consump) while calc1.current_year < start_year: calc1.increment_year() assert calc1.current_year == start_year # Create post-reform Calculator instance records2 = Records(data=taxrec_df.copy(deep=True), gfactors=growfactors_post) policy2 = Policy(gfactors=growfactors_post) policy_reform = user_mods['policy'] policy2.implement_reform(policy_reform) calc2 = Calculator(policy=policy2, records=records2, consumption=consump) while calc2.current_year < start_year: calc2.increment_year() assert calc2.current_year == start_year # Seed random number generator with a seed value based on user_mods seed = random_seed(user_mods) np.random.seed(seed) # pylint: disable=no-member for _ in range(0, year_n - 1): calc1.increment_year() calc2.increment_year() calc1.calc_all() calc2.calc_all() # Assert that the current year is one behind the year we are calculating assert (calc1.current_year + 1) == (start_year + year_n) assert (calc2.current_year + 1) == (start_year + year_n) # Compute gdp effect gdp_effect = proportional_change_gdp(calc1, calc2, gdp_elasticity) # Return gdp_effect results if return_json: gdp_df = pd.DataFrame(data=[gdp_effect], columns=['col0']) gdp_elast_names_i = [ x + '_' + str(year_n) for x in GDP_ELAST_ROW_NAMES ] gdp_elast_total = create_json_table(gdp_df, row_names=gdp_elast_names_i, num_decimals=5) gdp_elast_total = dict((k, v[0]) for k, v in gdp_elast_total.items()) return gdp_elast_total else: return gdp_effect
reforms_json = json.load(json_file) num_reforms = len(reforms_json) # create two calculators, one for baseline and the other for reforms tax_dta1 = pd.read_csv(PUF_PATH) records1 = Records(tax_dta1) policy1 = Policy(start_year=2013) calc1 = Calculator(records=records1, policy=policy1) tax_dta2 = pd.read_csv(PUF_PATH) records2 = Records(tax_dta2) policy2 = Policy(start_year=2013) calc2 = Calculator(records=records2, policy=policy2) # increment both calculators to 2015, when most reforms start calc1.increment_year() calc1.increment_year() calc2.increment_year() calc2.increment_year() # create a dictionary to save all results results = {} # runs one reform a time, each reform for 4 years # modify the number of reform & number of years as needed for i in range(1, num_reforms + 1): # make two deep copies so the originals could be used again in next loop c1 = copy.deepcopy(calc1) c2 = copy.deepcopy(calc2) # fetch this reform from json and implement in policy object
def dropq_calculate(year_n, start_year, taxrec_df, user_mods, behavior_allowed, mask_computed): """ The dropq_calculate function assumes specified user_mods is a dictionary returned by the Calculator.read_json_parameter_files() function with an extra key:value pair that is specified as 'gdp_elasticity': {'value': <float_value>}. The function returns (calc1, calc2, mask) where calc1 is pre-reform Calculator object calculated for year_n, calc2 is post-reform Calculator object calculated for year_n, and mask is boolean array if compute_mask=True or None otherwise """ # pylint: disable=too-many-arguments,too-many-locals,too-many-statements check_user_mods(user_mods) # specify Consumption instance consump = Consumption() consump_assumptions = user_mods['consumption'] consump.update_consumption(consump_assumptions) # specify growdiff_baseline and growdiff_response growdiff_baseline = Growdiff() growdiff_response = Growdiff() growdiff_base_assumps = user_mods['growdiff_baseline'] growdiff_resp_assumps = user_mods['growdiff_response'] growdiff_baseline.update_growdiff(growdiff_base_assumps) growdiff_response.update_growdiff(growdiff_resp_assumps) # create pre-reform and post-reform Growfactors instances growfactors_pre = Growfactors() growdiff_baseline.apply_to(growfactors_pre) growfactors_post = Growfactors() growdiff_baseline.apply_to(growfactors_post) growdiff_response.apply_to(growfactors_post) # create pre-reform Calculator instance recs1 = Records(data=taxrec_df.copy(deep=True), gfactors=growfactors_pre) policy1 = Policy(gfactors=growfactors_pre) calc1 = Calculator(policy=policy1, records=recs1, consumption=consump) while calc1.current_year < start_year: calc1.increment_year() calc1.calc_all() assert calc1.current_year == start_year # optionally compute mask if mask_computed: # create pre-reform Calculator instance with extra income recs1p = Records(data=taxrec_df.copy(deep=True), gfactors=growfactors_pre) # add one dollar to total wages and salaries of each filing unit recs1p.e00200 += 1.0 # pylint: disable=no-member recs1p.e00200p += 1.0 # pylint: disable=no-member policy1p = Policy(gfactors=growfactors_pre) # create Calculator with recs1p and calculate for start_year calc1p = Calculator(policy=policy1p, records=recs1p, consumption=consump) while calc1p.current_year < start_year: calc1p.increment_year() calc1p.calc_all() assert calc1p.current_year == start_year # compute mask that shows which of the calc1 and calc1p results differ res1 = results(calc1.records) res1p = results(calc1p.records) mask = (res1.iitax != res1p.iitax) else: mask = None # specify Behavior instance behv = Behavior() behavior_assumps = user_mods['behavior'] behv.update_behavior(behavior_assumps) # always prevent both behavioral response and growdiff response if behv.has_any_response() and growdiff_response.has_any_response(): msg = 'BOTH behavior AND growdiff_response HAVE RESPONSE' raise ValueError(msg) # optionally prevent behavioral response if behv.has_any_response() and not behavior_allowed: msg = 'A behavior RESPONSE IS NOT ALLOWED' raise ValueError(msg) # create post-reform Calculator instance recs2 = Records(data=taxrec_df.copy(deep=True), gfactors=growfactors_post) policy2 = Policy(gfactors=growfactors_post) policy_reform = user_mods['policy'] policy2.implement_reform(policy_reform) calc2 = Calculator(policy=policy2, records=recs2, consumption=consump, behavior=behv) while calc2.current_year < start_year: calc2.increment_year() calc2.calc_all() assert calc2.current_year == start_year # increment Calculator objects for year_n years and calculate for _ in range(0, year_n): calc1.increment_year() calc2.increment_year() calc1.calc_all() if calc2.behavior.has_response(): calc2 = Behavior.response(calc1, calc2) else: calc2.calc_all() # return calculated Calculator objects and mask return (calc1, calc2, mask)
def get_calculator(baseline, calculator_start_year, reform=None, data='cps', gfactors=None, weights=None, records_start_year=RECORDS_START_YEAR): ''' This function creates the tax calculator object for the microsim Args: baseline (bool): `True` if baseline tax policy calculator_start_year (integer): first year of budget window reform (dictionary): IIT reform parameters data (string or Pandas DataFrame): path to file or DataFrame for Tax-Calculator Records object (optional) weights (DataFrame): weights DataFrame for Tax-Calculator Records object (optional) records_start_year (integer): the start year for the data and weights dfs Returns: calc1 (Tax Calculator Calculator object): TC Calculator object with a current_year equal to calculator_start_year ''' # create a calculator policy1 = Policy() if data is not None and "cps" in data: records1 = Records.cps_constructor() # impute short and long term capital gains if using CPS data # in 2012 SOI data 6.587% of CG as short-term gains records1.p22250 = 0.06587 * records1.e01100 records1.p23250 = (1 - 0.06587) * records1.e01100 # set total capital gains to zero records1.e01100 = np.zeros(records1.e01100.shape[0]) elif data is not None: # pragma: no cover records1 = Records(data=data, gfactors=gfactors, weights=weights, start_year=records_start_year) # pragma: no cover else: records1 = Records() # pragma: no cover if baseline: # Should not be a reform if baseline is True assert not reform if not baseline: update_policy(policy1, reform) # the default set up increments year to 2013 calc1 = Calculator(records=records1, policy=policy1) print('Calculator initial year = ', calc1.current_year) # this increment_year function extrapolates all PUF variables to # the next year so this step takes the calculator to the start_year if calculator_start_year > TC_LAST_YEAR: raise RuntimeError("Start year is beyond data extrapolation.") while calc1.current_year < calculator_start_year: calc1.increment_year() return calc1
def calculators(year_n, start_year, use_puf_not_cps, use_full_sample, user_mods): """ This function assumes that the specified user_mods is a dictionary returned by the Calculator.read_json_param_objects() function. This function returns (calc1, calc2) where calc1 is pre-reform Calculator object for year_n, and calc2 is post-reform Calculator object for year_n. Neither Calculator object has had the calc_all() method executed. """ # pylint: disable=too-many-locals,too-many-branches,too-many-statements check_user_mods(user_mods) # specify Consumption instance consump = Consumption() consump_assumptions = user_mods['consumption'] consump.update_consumption(consump_assumptions) # specify growdiff_baseline and growdiff_response growdiff_baseline = GrowDiff() growdiff_response = GrowDiff() growdiff_base_assumps = user_mods['growdiff_baseline'] growdiff_resp_assumps = user_mods['growdiff_response'] growdiff_baseline.update_growdiff(growdiff_base_assumps) growdiff_response.update_growdiff(growdiff_resp_assumps) # create pre-reform and post-reform GrowFactors instances growfactors_pre = GrowFactors() growdiff_baseline.apply_to(growfactors_pre) growfactors_post = GrowFactors() growdiff_baseline.apply_to(growfactors_post) growdiff_response.apply_to(growfactors_post) # create sample pd.DataFrame from specified input file and sampling scheme tbi_path = os.path.abspath(os.path.dirname(__file__)) if use_puf_not_cps: # first try TaxBrain deployment path input_path = 'puf.csv.gz' if not os.path.isfile(input_path): # otherwise try local Tax-Calculator deployment path input_path = os.path.join(tbi_path, '..', '..', 'puf.csv') sampling_frac = 0.05 sampling_seed = 2222 else: # if using cps input not puf input # first try Tax-Calculator code path input_path = os.path.join(tbi_path, '..', 'cps.csv.gz') if not os.path.isfile(input_path): # otherwise read from taxcalc package "egg" input_path = None # pragma: no cover full_sample = read_egg_csv('cps.csv.gz') # pragma: no cover sampling_frac = 0.03 sampling_seed = 180 if input_path: full_sample = pd.read_csv(input_path) if use_full_sample: sample = full_sample else: sample = full_sample.sample(frac=sampling_frac, random_state=sampling_seed) # create pre-reform Calculator instance if use_puf_not_cps: recs1 = Records(data=sample, gfactors=growfactors_pre) else: recs1 = Records.cps_constructor(data=sample, gfactors=growfactors_pre) policy1 = Policy(gfactors=growfactors_pre) calc1 = Calculator(policy=policy1, records=recs1, consumption=consump) while calc1.current_year < start_year: calc1.increment_year() assert calc1.current_year == start_year # create post-reform Calculator instance if use_puf_not_cps: recs2 = Records(data=sample, gfactors=growfactors_post) else: recs2 = Records.cps_constructor(data=sample, gfactors=growfactors_post) policy2 = Policy(gfactors=growfactors_post) policy_reform = user_mods['policy'] policy2.implement_reform(policy_reform) calc2 = Calculator(policy=policy2, records=recs2, consumption=consump) while calc2.current_year < start_year: calc2.increment_year() assert calc2.current_year == start_year # delete objects now embedded in calc1 and calc2 del sample del full_sample del consump del growdiff_baseline del growdiff_response del growfactors_pre del growfactors_post del recs1 del recs2 del policy1 del policy2 # increment Calculator objects for year_n years for _ in range(0, year_n): calc1.increment_year() calc2.increment_year() # return Calculator objects return (calc1, calc2)
def calculate_baseline_and_reform(year_n, start_year, taxrec_df, user_mods): """ calculate_baseline_and_reform function assumes specified user_mods is a dictionary returned by the Calculator.read_json_parameter_files() function with an extra key:value pair that is specified as 'gdp_elasticity': {'value': <float_value>}. """ # pylint: disable=too-many-locals,too-many-branches,too-many-statements check_user_mods(user_mods) # Specify Consumption instance consump = Consumption() consump_assumptions = user_mods['consumption'] consump.update_consumption(consump_assumptions) # Specify growdiff_baseline and growdiff_response growdiff_baseline = Growdiff() growdiff_response = Growdiff() growdiff_base_assumps = user_mods['growdiff_baseline'] growdiff_resp_assumps = user_mods['growdiff_response'] growdiff_baseline.update_growdiff(growdiff_base_assumps) growdiff_response.update_growdiff(growdiff_resp_assumps) # Create pre-reform and post-reform Growfactors instances growfactors_pre = Growfactors() growdiff_baseline.apply_to(growfactors_pre) growfactors_post = Growfactors() growdiff_baseline.apply_to(growfactors_post) growdiff_response.apply_to(growfactors_post) # Create pre-reform Calculator instance recs1 = Records(data=taxrec_df.copy(deep=True), gfactors=growfactors_pre) policy1 = Policy(gfactors=growfactors_pre) calc1 = Calculator(policy=policy1, records=recs1, consumption=consump) while calc1.current_year < start_year: calc1.increment_year() calc1.calc_all() assert calc1.current_year == start_year # Create pre-reform Calculator instance with extra income recs1p = Records(data=taxrec_df.copy(deep=True), gfactors=growfactors_pre) # add one dollar to total wages and salaries of each filing unit recs1p.e00200 += 1.0 # pylint: disable=no-member policy1p = Policy(gfactors=growfactors_pre) calc1p = Calculator(policy=policy1p, records=recs1p, consumption=consump) while calc1p.current_year < start_year: calc1p.increment_year() calc1p.calc_all() assert calc1p.current_year == start_year # Construct mask to show which of the calc1 and calc1p results differ soit1 = results(calc1) soit1p = results(calc1p) mask = (soit1._iitax != soit1p._iitax) # pylint: disable=protected-access # Specify Behavior instance behv = Behavior() behavior_assumps = user_mods['behavior'] behv.update_behavior(behavior_assumps) # Prevent both behavioral response and growdiff response if behv.has_any_response() and growdiff_response.has_any_response(): msg = 'BOTH behavior AND growdiff_response HAVE RESPONSE' raise ValueError(msg) # Create post-reform Calculator instance with behavior recs2 = Records(data=taxrec_df.copy(deep=True), gfactors=growfactors_post) policy2 = Policy(gfactors=growfactors_post) policy_reform = user_mods['policy'] policy2.implement_reform(policy_reform) calc2 = Calculator(policy=policy2, records=recs2, consumption=consump, behavior=behv) while calc2.current_year < start_year: calc2.increment_year() calc2.calc_all() assert calc2.current_year == start_year # Seed random number generator with a seed value based on user_mods seed = random_seed(user_mods) print('seed={}'.format(seed)) np.random.seed(seed) # pylint: disable=no-member # Increment Calculator objects for year_n years and calculate for _ in range(0, year_n): calc1.increment_year() calc2.increment_year() calc1.calc_all() if calc2.behavior.has_response(): calc2 = Behavior.response(calc1, calc2) else: calc2.calc_all() # Return calculated results and mask soit1 = results(calc1) soit2 = results(calc2) return soit1, soit2, mask
def calculators(year_n, start_year, use_puf_not_cps, use_full_sample, user_mods): """ This function assumes that the specified user_mods is a dictionary returned by the Calculator.read_json_param_objects() function. This function returns (calc1, calc2) where calc1 is pre-reform Calculator object for year_n, and calc2 is post-reform Calculator object for year_n. Neither Calculator object has had the calc_all() method executed. """ # pylint: disable=too-many-locals,too-many-branches,too-many-statements check_user_mods(user_mods) # specify Consumption instance consump = Consumption() consump_assumptions = user_mods['consumption'] consump.update_consumption(consump_assumptions) # specify growdiff_baseline and growdiff_response growdiff_baseline = GrowDiff() growdiff_response = GrowDiff() growdiff_base_assumps = user_mods['growdiff_baseline'] growdiff_resp_assumps = user_mods['growdiff_response'] growdiff_baseline.update_growdiff(growdiff_base_assumps) growdiff_response.update_growdiff(growdiff_resp_assumps) # create pre-reform and post-reform GrowFactors instances growfactors_pre = GrowFactors() growdiff_baseline.apply_to(growfactors_pre) growfactors_post = GrowFactors() growdiff_baseline.apply_to(growfactors_post) growdiff_response.apply_to(growfactors_post) # create sample pd.DataFrame from specified input file and sampling scheme tbi_path = os.path.abspath(os.path.dirname(__file__)) if use_puf_not_cps: # first try TaxBrain deployment path input_path = 'puf.csv.gz' if not os.path.isfile(input_path): # otherwise try local Tax-Calculator deployment path input_path = os.path.join(tbi_path, '..', '..', 'puf.csv') sampling_frac = 0.05 sampling_seed = 2222 else: # if using cps input not puf input # first try Tax-Calculator code path input_path = os.path.join(tbi_path, '..', 'cps.csv.gz') if not os.path.isfile(input_path): # otherwise read from taxcalc package "egg" input_path = None # pragma: no cover full_sample = read_egg_csv('cps.csv.gz') # pragma: no cover sampling_frac = 0.03 sampling_seed = 180 if input_path: full_sample = pd.read_csv(input_path) if use_full_sample: sample = full_sample else: sample = full_sample.sample(frac=sampling_frac, random_state=sampling_seed) # create pre-reform Calculator instance if use_puf_not_cps: recs1 = Records(data=sample, gfactors=growfactors_pre) else: recs1 = Records.cps_constructor(data=sample, gfactors=growfactors_pre) policy1 = Policy(gfactors=growfactors_pre) calc1 = Calculator(policy=policy1, records=recs1, consumption=consump) while calc1.current_year < start_year: calc1.increment_year() assert calc1.current_year == start_year # create post-reform Calculator instance if use_puf_not_cps: recs2 = Records(data=sample, gfactors=growfactors_post) else: recs2 = Records.cps_constructor(data=sample, gfactors=growfactors_post) policy2 = Policy(gfactors=growfactors_post) policy_reform = user_mods['policy'] policy2.implement_reform(policy_reform) calc2 = Calculator(policy=policy2, records=recs2, consumption=consump) while calc2.current_year < start_year: calc2.increment_year() assert calc2.current_year == start_year # delete objects now embedded in calc1 and calc2 del sample del full_sample del consump del growdiff_baseline del growdiff_response del growfactors_pre del growfactors_post del recs1 del recs2 del policy1 del policy2 # increment Calculator objects for year_n years for _ in range(0, year_n): calc1.increment_year() calc2.increment_year() # return Calculator objects return (calc1, calc2)
def run_nth_year_mtr_calc(year_n, start_year, tax_dta, user_mods="", return_json=True): #Only makes sense to run for budget years 1 through n-1 (not for year 0) assert year_n > 0 elasticity_gdp = elasticity_of_gdp_year_n(user_mods, year_n) ######################################################################### # Create Calculators and Masks ######################################################################### records = Records(tax_dta.copy(deep=True)) records3 = Records(tax_dta.copy(deep=True)) # Default Plans # Create a default Policy object params = Policy(start_year=2013) # Create a Calculator calc1 = Calculator(policy=params, records=records) growth_assumptions = only_growth_assumptions(user_mods, start_year) if growth_assumptions: calc1.growth.update_economic_growth(growth_assumptions) while calc1.current_year < start_year: calc1.increment_year() assert calc1.current_year == start_year # User specified Plans reform_mods = only_reform_mods(user_mods, start_year) params3 = Policy(start_year=2013) params3.implement_reform(reform_mods) behavior3 = Behavior(start_year=2013) # Create a Calculator for the user specified plan calc3 = Calculator(policy=params3, records=records3, behavior=behavior3) if growth_assumptions: calc3.growth.update_economic_growth(growth_assumptions) while calc3.current_year < start_year: calc3.increment_year() assert calc3.current_year == start_year # Get a random seed based on user specified plan seed = random_seed_from_plan(calc3) np.random.seed(seed) for i in range(0, year_n-1): calc1.increment_year() calc3.increment_year() calc1.calc_all() calc3.calc_all() mtr_fica_x, mtr_iit_x, mtr_combined_x = calc1.mtr() mtr_fica_y, mtr_iit_y, mtr_combined_y = calc3.mtr() #Assert that the current year is one behind the year we are calculating assert (calc1.current_year + 1) == (start_year + year_n) assert (calc3.current_year + 1) == (start_year + year_n) after_tax_mtr_x = 1 - ((mtr_combined_x * calc1.records.c00100 * calc1.records.s006).sum()/ (calc1.records.c00100 * calc1.records.s006).sum()) after_tax_mtr_y = 1 - ((mtr_combined_y * calc3.records.c00100 * calc3.records.s006).sum()/ (calc3.records.c00100 * calc3.records.s006).sum()) diff_avg_mtr_combined_y = after_tax_mtr_y - after_tax_mtr_x percent_diff_mtr = diff_avg_mtr_combined_y / after_tax_mtr_x gdp_effect_y = percent_diff_mtr * elasticity_gdp gdp_df = pd.DataFrame(data=[gdp_effect_y], columns=["col0"]) if not return_json: return gdp_effect_y gdp_elast_names_i = [x+'_'+str(year_n) for x in GDP_elasticity_row_names] gdp_elast_total = create_json_table(gdp_df, row_names=gdp_elast_names_i, num_decimals=5) # Make the one-item lists of strings just strings gdp_elast_total = dict((k, v[0]) for k,v in gdp_elast_total.items()) return gdp_elast_total
num_reforms = len(reforms_json) # create two calculators, one for baseline and the other for reforms tax_dta1 = pd.read_csv(PUF_PATH) records1 = Records(tax_dta1) policy1 = Policy(start_year=2013) calc1 = Calculator(records=records1, policy=policy1) tax_dta2 = pd.read_csv(PUF_PATH) records2 = Records(tax_dta2) policy2 = Policy(start_year=2013) calc2 = Calculator(records=records2, policy=policy2) # increment both calculators to 2015, when most reforms start calc1.increment_year() calc1.increment_year() calc2.increment_year() calc2.increment_year() # create a dictionary to save all results results = {} # runs one reform a time, each reform for 4 years # modify the number of reform & number of years as needed for i in range(1, num_reforms + 1): # make two deep copies so the originals could be used again in next loop c1 = copy.deepcopy(calc1) c2 = copy.deepcopy(calc2) # fetch this reform from json and implement in policy object