Recipe 1: Directly Comparing Two Reforms#

This is an advanced recipe that should be followed only after mastering the basic recipe. This recipe shows how to compare two reforms (instead of comparing a reform to current-law policy) and also shows how to use the reform files available on the Tax-Calculator website (instead of reform files on your computer’s disk).

import pandas as pd
import taxcalc as tc

# read an "old" reform file
# ("old" means the reform file is defined relative to pre-TCJA policy)
# specify reform dictionary for pre-TCJA policy
reform1 = tc.Policy.read_json_reform('github://PSLmodels:[email protected]/psl_examples/taxcalc/2017_law.json')

# specify reform dictionary for TCJA as passed by Congress in late 2017
reform2 = tc.Policy.read_json_reform('github://PSLmodels:[email protected]/psl_examples/taxcalc/TCJA.json')

# specify Policy object for pre-TCJA policy
bpolicy = tc.Policy()
bpolicy.implement_reform(reform1, print_warnings=False, raise_errors=False)
assert not bpolicy.parameter_errors

# specify Policy object for TCJA reform relative to pre-TCJA policy
rpolicy = tc.Policy()
rpolicy.implement_reform(reform1, print_warnings=False, raise_errors=False)
assert not rpolicy.parameter_errors
rpolicy.implement_reform(reform2, print_warnings=False, raise_errors=False)
assert not rpolicy.parameter_errors

# specify Calculator objects using bpolicy and rpolicy
recs = tc.Records.cps_constructor()
calc1 = tc.Calculator(policy=bpolicy, records=recs)
calc2 = tc.Calculator(policy=rpolicy, records=recs)

CYR = 2018

# calculate for specified CYR
calc1.advance_to_year(CYR)
calc1.calc_all()
calc2.advance_to_year(CYR)
calc2.calc_all()

# compare aggregate individual income tax revenue in cyr
iitax_rev1 = calc1.weighted_total('iitax')
iitax_rev2 = calc2.weighted_total('iitax')

# construct reform-vs-baseline difference table with results for income deciles
diff_table = calc1.difference_table(calc2, 'weighted_deciles', 'iitax')
assert isinstance(diff_table, pd.DataFrame)
diff_extract = pd.DataFrame()
dif_colnames = ['count', 'tax_cut', 'tax_inc',
                'tot_change', 'mean', 'pc_aftertaxinc']
ext_colnames = ['funits(#m)', 'taxfall(#m)', 'taxrise(#m)',
                'agg_diff($b)', 'mean_diff($)', 'aftertax_income_diff(%)']
for dname, ename in zip(dif_colnames, ext_colnames):
    diff_extract[ename] = diff_table[dname]

# print total revenue estimates for cyr
# (estimates in billons of dollars)
print('{}_REFORM1_iitax_rev($B)= {:.3f}'.format(CYR, iitax_rev1 * 1e-9))
print('{}_REFORM2_iitax_rev($B)= {:.3f}'.format(CYR, iitax_rev2 * 1e-9))
print('')
2018_REFORM1_iitax_rev($B)= 1361.860
2018_REFORM2_iitax_rev($B)= 1195.986

Print reform2-vs-reform1 difference table

title = 'Extract of {} income-tax difference table by expanded-income decile'
print(title.format(CYR))
print('(taxfall is count of funits with cut in income tax in reform 2 vs 1)')
print('(taxrise is count of funits with rise in income tax in reform 2 vs 1)')
print(diff_extract.to_string())
Extract of 2018 income-tax difference table by expanded-income decile
(taxfall is count of funits with cut in income tax in reform 2 vs 1)
(taxrise is count of funits with rise in income tax in reform 2 vs 1)
        funits(#m)  taxfall(#m)  taxrise(#m)  agg_diff($b)  mean_diff($)  aftertax_income_diff(%)
0-10n     0.099742     0.000000     0.000000      0.000000      0.000000                 0.000000
0-10z     8.084653     0.000000     0.000000      0.000000      0.000000                      NaN
0-10p    11.735831     0.169713     0.011669     -0.011944     -1.017723                 0.031206
10-20    19.920848     6.252514     2.881016     -0.773068    -38.806967                 0.322053
20-30    19.920146    10.132046     2.388090     -1.883900    -94.572611                 0.416364
30-40    19.920561     9.240418     2.014589     -3.487306   -175.060636                 0.568271
40-50    19.919924    11.020755     2.138903     -5.811259   -291.730960                 0.764025
50-60    19.922029    13.167126     2.068208     -8.677724   -435.584355                 0.915270
60-70    19.920346    14.128191     1.779769    -11.880018   -596.376071                 0.992883
70-80    19.917057    15.548090     1.521095    -17.000699   -853.574853                 1.121701
80-90    19.923101    16.962688     1.655445    -26.051374  -1307.596379                 1.292798
90-100   19.922247    18.151020     1.515929    -90.296170  -4532.428923                 2.135097
ALL     199.206484   114.772563    17.974713   -165.873461   -832.670994                 1.381893
90-95     9.961787     8.958237     0.772773    -22.392909  -2247.880826                 1.646789
95-99     7.965885     7.393762     0.547601    -37.425684  -4698.245725                 2.281880
Top 1%    1.994576     1.799021     0.195555    -30.477576 -15280.229968                 2.479426