taxcalc 4.2.1__py3-none-any.whl → 4.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- taxcalc/__init__.py +1 -1
- taxcalc/assumptions/ASSUMPTIONS.md +53 -0
- taxcalc/assumptions/README.md +17 -0
- taxcalc/assumptions/economic_assumptions_template.json +77 -0
- taxcalc/calcfunctions.py +7 -4
- taxcalc/data.py +10 -5
- taxcalc/policy.py +1 -1
- taxcalc/policy_current_law.json +4649 -288
- taxcalc/records.py +20 -15
- taxcalc/reforms/2017_law.json +125 -0
- taxcalc/reforms/2017_law.out.csv +10 -0
- taxcalc/reforms/ARPA.json +78 -0
- taxcalc/reforms/ARPA.out.csv +10 -0
- taxcalc/reforms/BrownKhanna.json +23 -0
- taxcalc/reforms/BrownKhanna.out.csv +10 -0
- taxcalc/reforms/CARES.json +40 -0
- taxcalc/reforms/CARES.out.csv +10 -0
- taxcalc/reforms/ConsolidatedAppropriationsAct2021.json +15 -0
- taxcalc/reforms/ConsolidatedAppropriationsAct2021.out.csv +10 -0
- taxcalc/reforms/Larson2019.json +36 -0
- taxcalc/reforms/Larson2019.out.csv +10 -0
- taxcalc/reforms/README.md +22 -0
- taxcalc/reforms/REFORMS.md +92 -0
- taxcalc/reforms/Renacci.json +61 -0
- taxcalc/reforms/Renacci.out.csv +10 -0
- taxcalc/reforms/SandersDeFazio.json +15 -0
- taxcalc/reforms/SandersDeFazio.out.csv +10 -0
- taxcalc/reforms/TCJA.json +160 -0
- taxcalc/reforms/TCJA.md +48 -0
- taxcalc/reforms/TCJA.out.csv +10 -0
- taxcalc/reforms/Trump2016.json +71 -0
- taxcalc/reforms/Trump2016.out.csv +10 -0
- taxcalc/reforms/Trump2017.json +51 -0
- taxcalc/reforms/Trump2017.out.csv +10 -0
- taxcalc/reforms/archive/Clinton2016.json +56 -0
- taxcalc/reforms/archive/RyanBrady.json +104 -0
- taxcalc/reforms/archive/TCJA_House.json +144 -0
- taxcalc/reforms/archive/TCJA_House_Amended.json +152 -0
- taxcalc/reforms/archive/TCJA_Reconciliation.json +187 -0
- taxcalc/reforms/archive/TCJA_Senate.json +116 -0
- taxcalc/reforms/archive/TCJA_Senate_111417.json +169 -0
- taxcalc/reforms/archive/TCJA_Senate_120117.json +174 -0
- taxcalc/reforms/cases.csv +10 -0
- taxcalc/reforms/clp.out.csv +10 -0
- taxcalc/reforms/ext.json +59 -0
- taxcalc/reforms/growfactors_ext.csv +65 -0
- taxcalc/reforms/ptaxes0.json +37 -0
- taxcalc/reforms/ptaxes0.out.csv +10 -0
- taxcalc/reforms/ptaxes1.json +21 -0
- taxcalc/reforms/ptaxes1.out.csv +10 -0
- taxcalc/reforms/ptaxes2.json +18 -0
- taxcalc/reforms/ptaxes2.out.csv +10 -0
- taxcalc/reforms/ptaxes3.json +28 -0
- taxcalc/reforms/ptaxes3.out.csv +10 -0
- taxcalc/taxcalcio.py +44 -22
- taxcalc/tests/benefits_expect.csv +169 -0
- taxcalc/tests/cmpi_cps_expect.txt +132 -0
- taxcalc/tests/cmpi_puf_expect.txt +132 -0
- taxcalc/tests/conftest.py +143 -0
- taxcalc/tests/cpscsv_agg_expect.csv +26 -0
- taxcalc/tests/puf_var_correl_coeffs_2016.csv +80 -0
- taxcalc/tests/puf_var_wght_means_by_year.csv +80 -0
- taxcalc/tests/pufcsv_agg_expect.csv +26 -0
- taxcalc/tests/pufcsv_mtr_expect.txt +63 -0
- taxcalc/tests/reforms.json +649 -0
- taxcalc/tests/reforms_expect.csv +65 -0
- taxcalc/tests/test_4package.py +67 -0
- taxcalc/tests/test_benefits.py +86 -0
- taxcalc/tests/test_calcfunctions.py +871 -0
- taxcalc/tests/test_calculator.py +1021 -0
- taxcalc/tests/test_compare.py +336 -0
- taxcalc/tests/test_compatible_data.py +338 -0
- taxcalc/tests/test_consumption.py +144 -0
- taxcalc/tests/test_cpscsv.py +163 -0
- taxcalc/tests/test_data.py +133 -0
- taxcalc/tests/test_decorators.py +332 -0
- taxcalc/tests/test_growdiff.py +102 -0
- taxcalc/tests/test_growfactors.py +94 -0
- taxcalc/tests/test_parameters.py +617 -0
- taxcalc/tests/test_policy.py +1557 -0
- taxcalc/tests/test_puf_var_stats.py +194 -0
- taxcalc/tests/test_pufcsv.py +385 -0
- taxcalc/tests/test_records.py +234 -0
- taxcalc/tests/test_reforms.py +386 -0
- taxcalc/tests/test_responses.py +41 -0
- taxcalc/tests/test_taxcalcio.py +755 -0
- taxcalc/tests/test_utils.py +792 -0
- taxcalc/validation/CSV_INPUT_VARS.md +29 -0
- taxcalc/validation/CSV_OUTPUT_VARS.md +63 -0
- taxcalc/validation/README.md +68 -0
- taxcalc/validation/taxsim35/Differences_Explained.md +54 -0
- taxcalc/validation/taxsim35/README.md +139 -0
- taxcalc/validation/taxsim35/expected_differences/a17-taxdiffs-expect.csv +25 -0
- taxcalc/validation/taxsim35/expected_differences/a18-taxdiffs-expect.csv +25 -0
- taxcalc/validation/taxsim35/expected_differences/a19-taxdiffs-expect.csv +25 -0
- taxcalc/validation/taxsim35/expected_differences/a20-taxdiffs-expect.csv +25 -0
- taxcalc/validation/taxsim35/expected_differences/a21-taxdiffs-expect.csv +25 -0
- taxcalc/validation/taxsim35/expected_differences/b17-taxdiffs-expect.csv +25 -0
- taxcalc/validation/taxsim35/expected_differences/b18-taxdiffs-expect.csv +25 -0
- taxcalc/validation/taxsim35/expected_differences/b19-taxdiffs-expect.csv +25 -0
- taxcalc/validation/taxsim35/expected_differences/b20-taxdiffs-expect.csv +25 -0
- taxcalc/validation/taxsim35/expected_differences/b21-taxdiffs-expect.csv +25 -0
- taxcalc/validation/taxsim35/expected_differences/c17-taxdiffs-expect.csv +25 -0
- taxcalc/validation/taxsim35/expected_differences/c18-taxdiffs-expect.csv +25 -0
- taxcalc/validation/taxsim35/expected_differences/c19-taxdiffs-expect.csv +25 -0
- taxcalc/validation/taxsim35/input_setup.py +67 -0
- taxcalc/validation/taxsim35/main_comparison.py +183 -0
- taxcalc/validation/taxsim35/prepare_taxcalc_input.py +161 -0
- taxcalc/validation/taxsim35/process_taxcalc_output.py +140 -0
- taxcalc/validation/taxsim35/taxsim_emulation.json +49 -0
- taxcalc/validation/taxsim35/taxsim_input.py +321 -0
- taxcalc/validation/taxsim35/tc_sims.py +98 -0
- taxcalc/validation/taxsim35/tests_35.py +80 -0
- taxcalc/validation/tests_35.sh +13 -0
- {taxcalc-4.2.1.dist-info → taxcalc-4.3.0.dist-info}/METADATA +3 -4
- taxcalc-4.3.0.dist-info/RECORD +139 -0
- {taxcalc-4.2.1.dist-info → taxcalc-4.3.0.dist-info}/WHEEL +1 -1
- taxcalc/tmd_growfactors.csv +0 -55
- taxcalc/tmd_weights.csv.gz +0 -0
- taxcalc-4.2.1.dist-info/RECORD +0 -34
- {taxcalc-4.2.1.dist-info → taxcalc-4.3.0.dist-info}/LICENSE +0 -0
- {taxcalc-4.2.1.dist-info → taxcalc-4.3.0.dist-info}/entry_points.txt +0 -0
- {taxcalc-4.2.1.dist-info → taxcalc-4.3.0.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,25 @@
|
|
1
|
+
,# of differing records,max_diff,max_diff_index,max_diff_taxsim_val,max_diff_taxcalc_val
|
2
|
+
iitax,1000,-27840.640000000014,246,246001.89,218161.25
|
3
|
+
statetax,0,0.0,no diff,no diff,no diff
|
4
|
+
payrolltax,939,15897.900000000001,861,39167.24,55065.14
|
5
|
+
mtr_inctax,384,-21.490000000000002,17,50.49,29.0
|
6
|
+
mtr_state,0,0.0,no diff,no diff,no diff
|
7
|
+
c00100,573,-7949.859999999986,861,963275.51,955325.65
|
8
|
+
e02300,0,0.0,no diff,no diff,no diff
|
9
|
+
c02500,0,0.0,no diff,no diff,no diff
|
10
|
+
post_phase_out_pe,0,0.0,no diff,no diff,no diff
|
11
|
+
phased_out_pe,0,0.0,no diff,no diff,no diff
|
12
|
+
c21040,0,0.0,no diff,no diff,no diff
|
13
|
+
c04470,0,0.0,no diff,no diff,no diff
|
14
|
+
c04800,1000,-75244.97999999998,246,828115.91,752870.93
|
15
|
+
taxbc,1000,-32292.660000000003,956,229141.22,196848.56
|
16
|
+
exemption_surtax,0,0.0,no diff,no diff,no diff
|
17
|
+
gen_tax_credit,0,0.0,no diff,no diff,no diff
|
18
|
+
non_refundable_child_odep_credit,12,234.75,561,1293.63,1528.38
|
19
|
+
c11070,0,0.0,no diff,no diff,no diff
|
20
|
+
c07180,0,0.0,no diff,no diff,no diff
|
21
|
+
eitc,0,0.0,no diff,no diff,no diff
|
22
|
+
c62100,1000,-75244.97999999998,246,854715.91,779470.93
|
23
|
+
amt_liability,0,0.0,no diff,no diff,no diff
|
24
|
+
iitax_before_credits_ex_AMT,1000,-27840.640000000014,246,245271.89,217431.25
|
25
|
+
recovery_rebate_credit,0,0.0,no diff,no diff,no diff
|
@@ -0,0 +1,25 @@
|
|
1
|
+
,# of differing records,max_diff,max_diff_index,max_diff_taxsim_val,max_diff_taxcalc_val
|
2
|
+
iitax,1000,-27608.780000000028,837,312222.07,284613.29
|
3
|
+
statetax,0,0.0,no diff,no diff,no diff
|
4
|
+
payrolltax,942,16454.309999999998,873,46662.91,63117.22
|
5
|
+
mtr_inctax,366,-19.259999999999998,130,48.26,29.0
|
6
|
+
mtr_state,0,0.0,no diff,no diff,no diff
|
7
|
+
c00100,550,-8228.23999999999,873,1128648.72,1120420.48
|
8
|
+
e02300,0,0.0,no diff,no diff,no diff
|
9
|
+
c02500,0,0.0,no diff,no diff,no diff
|
10
|
+
post_phase_out_pe,0,0.0,no diff,no diff,no diff
|
11
|
+
phased_out_pe,0,0.0,no diff,no diff,no diff
|
12
|
+
c21040,0,0.0,no diff,no diff,no diff
|
13
|
+
c04470,0,0.0,no diff,no diff,no diff
|
14
|
+
c04800,1000,-74618.33999999997,837,1015746.15,941127.81
|
15
|
+
taxbc,1000,-29988.790000000037,837,313966.08,283977.29
|
16
|
+
exemption_surtax,0,0.0,no diff,no diff,no diff
|
17
|
+
gen_tax_credit,0,0.0,no diff,no diff,no diff
|
18
|
+
non_refundable_child_odep_credit,10,382.96000000000004,3,3128.1,3511.06
|
19
|
+
c11070,0,0.0,no diff,no diff,no diff
|
20
|
+
c07180,0,0.0,no diff,no diff,no diff
|
21
|
+
eitc,0,0.0,no diff,no diff,no diff
|
22
|
+
c62100,1000,-74618.33999999997,837,1025746.15,951127.81
|
23
|
+
amt_liability,0,0.0,no diff,no diff,no diff
|
24
|
+
iitax_before_credits_ex_AMT,1000,-27608.780000000028,837,311586.07,283977.29
|
25
|
+
recovery_rebate_credit,0,0.0,no diff,no diff,no diff
|
@@ -0,0 +1,67 @@
|
|
1
|
+
"""
|
2
|
+
Generates TAXSIM-35 `.in` input files, downloads `.in.out-taxsim` output files,
|
3
|
+
prepares files for Tax Calculator and zips them
|
4
|
+
"""
|
5
|
+
|
6
|
+
import os
|
7
|
+
import glob
|
8
|
+
import taxsim_input
|
9
|
+
|
10
|
+
|
11
|
+
def get_ftp_output(letter, year):
|
12
|
+
"""
|
13
|
+
Uses `curl` to upload assumption set input files
|
14
|
+
and save taxsim-35 output files
|
15
|
+
|
16
|
+
Args:
|
17
|
+
letter (character): letter denoting assumption set to generate data
|
18
|
+
year (int): year data will represent
|
19
|
+
offset (int): offset to alter the random number seed
|
20
|
+
|
21
|
+
Returns:
|
22
|
+
None
|
23
|
+
"""
|
24
|
+
f = str(letter + str(year) + ".in")
|
25
|
+
file_out = f + ".out-taxsim"
|
26
|
+
os.system(
|
27
|
+
f"ssh -T -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null taxsim35@taxsim35.nber.org <{f} >{file_out}"
|
28
|
+
)
|
29
|
+
|
30
|
+
|
31
|
+
def change_delim(letter, year):
|
32
|
+
""" "
|
33
|
+
This function changes the delimeter in the taxsim output files from
|
34
|
+
a comma to a space
|
35
|
+
|
36
|
+
This is necessary because taxsim output seems to vary - for some years
|
37
|
+
the separator is a comma and for others (seemingly before 2020) it's a space
|
38
|
+
|
39
|
+
Args:
|
40
|
+
letter (character): letter denoting assumption set to generate data
|
41
|
+
year (int): year data will represent
|
42
|
+
offset (int): offset to alter the random number seed
|
43
|
+
|
44
|
+
Returns:
|
45
|
+
None
|
46
|
+
"""
|
47
|
+
f = str(letter + str(year) + ".in")
|
48
|
+
file_out = f + ".out-taxsim"
|
49
|
+
# Read in the file
|
50
|
+
with open(file_out, "r") as fin:
|
51
|
+
filedata = fin.read()
|
52
|
+
|
53
|
+
# Replace the target string
|
54
|
+
# filedata = filedata.replace(",", " ")
|
55
|
+
filedata = filedata.replace(" ", "")
|
56
|
+
|
57
|
+
# Write the file out again
|
58
|
+
with open(file_out, "w") as fout:
|
59
|
+
fout.write(filedata)
|
60
|
+
|
61
|
+
|
62
|
+
def taxsim_io(assump_set, years):
|
63
|
+
for letter in assump_set:
|
64
|
+
for year in years:
|
65
|
+
taxsim_input.generate_datasets(letter, year)
|
66
|
+
get_ftp_output(letter, year)
|
67
|
+
change_delim(letter, year)
|
@@ -0,0 +1,183 @@
|
|
1
|
+
# DESCRIPTIONS of variable outputs can be found on the TAXSIM-35 website near
|
2
|
+
# the bottom of the page
|
3
|
+
# URL: https://users.nber.org/~taxsim/taxsim35/
|
4
|
+
|
5
|
+
import sys
|
6
|
+
import os
|
7
|
+
import pandas as pd
|
8
|
+
import numpy as np
|
9
|
+
import tc_sims
|
10
|
+
|
11
|
+
CUR_PATH = os.path.abspath(os.path.dirname(__file__))
|
12
|
+
# check if directory exists, if not create it
|
13
|
+
if not os.path.isdir(os.path.join(CUR_PATH, "actual_differences")):
|
14
|
+
os.mkdir(os.path.join(CUR_PATH, "actual_differences"))
|
15
|
+
|
16
|
+
|
17
|
+
def main(letter, year):
|
18
|
+
|
19
|
+
test_passed = False # set boolean to False, change in tests pass
|
20
|
+
# (1) generate TAXSIM-35-formatted output using Tax-Calculator tc CLI
|
21
|
+
tc_sims.io(letter, year)
|
22
|
+
|
23
|
+
# (2) generate tax differences
|
24
|
+
print("Trying to read ", f"{letter}{year}.in.out-taxsim")
|
25
|
+
taxsim_df = pd.read_csv(
|
26
|
+
f"{letter}{year}.in.out-taxsim",
|
27
|
+
# skipinitialspace=True,
|
28
|
+
# delim_whitespace=True,
|
29
|
+
index_col=False,
|
30
|
+
)
|
31
|
+
# taxsim_df = taxsim_df.iloc[:, 0:28]
|
32
|
+
taxcalc_df = pd.read_csv(
|
33
|
+
f"{letter}{year}.in.out-taxcalc",
|
34
|
+
# skipinitialspace=True,
|
35
|
+
index_col=0,
|
36
|
+
)
|
37
|
+
|
38
|
+
taxsim_out_cols_map = {
|
39
|
+
"taxsimid": "RECID",
|
40
|
+
"year": "FLPDYR",
|
41
|
+
"state": "state",
|
42
|
+
"fiitax": "iitax",
|
43
|
+
"siitax": "statetax",
|
44
|
+
"fica": "payrolltax",
|
45
|
+
"frate": "mtr_inctax",
|
46
|
+
"srate": "mtr_state",
|
47
|
+
# "ficar": "mtr_paytax", # not sure why, but this is always zero from taxsim
|
48
|
+
# "tfica": "ptax_oasdi", # I don't understand how fica and tfica differ in taxsim
|
49
|
+
"v10": "c00100", # federal agi
|
50
|
+
"v11": "e02300", # UI in federal AGI
|
51
|
+
"v12": "c02500", # social security in AGI
|
52
|
+
# "v13": "zero_bracket_amount", # zero bracket amount (for itemizers) -- always set to zero in taxcalc output
|
53
|
+
"v14": "post_phase_out_pe", # personal exemptions
|
54
|
+
"v15": "phased_out_pe", # exemption phaseout
|
55
|
+
"v16": "c21040", # deduction phaseout
|
56
|
+
"v17": "c04470", # itemized deductions
|
57
|
+
"v18": "c04800", # federal taxable income
|
58
|
+
"v19": "taxbc", # tax on taxable income (no special cap gains rates)
|
59
|
+
"v20": "exemption_surtax", # exemption surtax -- always set to zero in taxcalc output
|
60
|
+
"v21": "gen_tax_credit", # general tax credit -- always set to zero in taxcalc output
|
61
|
+
"v22": "non_refundable_child_odep_credit", # child tax credit (as adjusted) # Is this right?? Should it be c07220 only?
|
62
|
+
"v23": "c11070", # additional child tax credit (refundable)
|
63
|
+
"v24": "c07180", # child care credit
|
64
|
+
"v25": "eitc", # earned income credit (total federal)
|
65
|
+
"v26": "c62100", # income for amt
|
66
|
+
"v27": "amt_liability", # AMT liability
|
67
|
+
"v28": "iitax_before_credits_ex_AMT", # federal tax before credits
|
68
|
+
# "v29": , # FICA -- is this not the same as "fica" above?
|
69
|
+
# state calculations all zeros since we don't do state calculations
|
70
|
+
# "v30": , #state household income
|
71
|
+
# "v31": , # state rent expense
|
72
|
+
# "v32": , # state AGI
|
73
|
+
# "v33": , # state exemption amount
|
74
|
+
# "v34": , # state standard deduction
|
75
|
+
# "v35": , # state itemized deductions
|
76
|
+
# "v36": , # state taxable income
|
77
|
+
# "v37": , # state property tax credit
|
78
|
+
# "v38": , # state child care tax credit
|
79
|
+
# "v39": , # state EIC
|
80
|
+
# "v40": , # state total credits
|
81
|
+
# "v41": , # state bracket rate
|
82
|
+
# "v42": , # earned self-employed income for FICA
|
83
|
+
# "v43": , # medicare tax on unearned income
|
84
|
+
# "v44": , # medicare tax on earned income
|
85
|
+
"v45": "recovery_rebate_credit", # CARES act Recovery Rebates
|
86
|
+
# "v46": ,
|
87
|
+
# "v47": ,
|
88
|
+
}
|
89
|
+
|
90
|
+
# give tax-calculator variable names to taxsim output variables
|
91
|
+
taxsim_df.rename(columns=taxsim_out_cols_map, inplace=True)
|
92
|
+
taxsim_df = taxsim_df[list(taxsim_out_cols_map.values())]
|
93
|
+
|
94
|
+
diff_dict = {
|
95
|
+
"# of differing records": [],
|
96
|
+
"max_diff": [],
|
97
|
+
"max_diff_index": [],
|
98
|
+
"max_diff_taxsim_val": [],
|
99
|
+
"max_diff_taxcalc_val": [],
|
100
|
+
}
|
101
|
+
diff_df = taxcalc_df - taxsim_df
|
102
|
+
input_df = pd.read_csv(
|
103
|
+
f"{letter}{year}.in",
|
104
|
+
# skipinitialspace=True,
|
105
|
+
# delim_whitespace=True,
|
106
|
+
index_col=False,
|
107
|
+
)
|
108
|
+
with pd.ExcelWriter(
|
109
|
+
os.path.join(
|
110
|
+
CUR_PATH, "actual_differences", f"{letter}{year}differences.xlsx"
|
111
|
+
)
|
112
|
+
) as writer:
|
113
|
+
# use to_excel function and specify the sheet_name and index
|
114
|
+
# to store the dataframe in specified sheet
|
115
|
+
taxsim_df.to_excel(writer, sheet_name="taxsim", index=False)
|
116
|
+
taxcalc_df.to_excel(writer, sheet_name="taxcalc", index=False)
|
117
|
+
diff_df.to_excel(writer, sheet_name="differences", index=False)
|
118
|
+
input_df.to_excel(writer, sheet_name="inputs", index=False)
|
119
|
+
|
120
|
+
for col in taxsim_df.columns[3:]:
|
121
|
+
df_diff = pd.DataFrame({"a": taxsim_df[col], "b": taxcalc_df[col]})
|
122
|
+
df_diff_recs = df_diff[df_diff["a"] != df_diff["b"]]
|
123
|
+
diff_dict["# of differing records"].append(df_diff_recs.shape[0])
|
124
|
+
|
125
|
+
ind, max_val = max(
|
126
|
+
enumerate(
|
127
|
+
abs(x - y)
|
128
|
+
for x, y in zip(taxcalc_df.loc[:, col], taxsim_df.loc[:, col])
|
129
|
+
),
|
130
|
+
key=lambda x: x[1],
|
131
|
+
)
|
132
|
+
|
133
|
+
diff_dict["max_diff"].append(
|
134
|
+
taxcalc_df.loc[ind, col] - taxsim_df.loc[ind, col]
|
135
|
+
)
|
136
|
+
if max_val != 0:
|
137
|
+
diff_dict["max_diff_index"].append(ind)
|
138
|
+
diff_dict["max_diff_taxsim_val"].append(taxsim_df.loc[ind, col])
|
139
|
+
diff_dict["max_diff_taxcalc_val"].append(taxcalc_df.loc[ind, col])
|
140
|
+
else:
|
141
|
+
diff_dict["max_diff_index"].append("no diff")
|
142
|
+
diff_dict["max_diff_taxsim_val"].append("no diff")
|
143
|
+
diff_dict["max_diff_taxcalc_val"].append("no diff")
|
144
|
+
|
145
|
+
actual_df = pd.DataFrame(diff_dict, index=taxsim_df.columns[3:])
|
146
|
+
print(
|
147
|
+
f"Difference in dataframes for assumption set {letter} in year {year}"
|
148
|
+
)
|
149
|
+
print(actual_df)
|
150
|
+
|
151
|
+
# (3) check for difference between LYY.taxdiffs-actual and LYY.taxdiffs-expect
|
152
|
+
expected_file_name = os.path.join(
|
153
|
+
CUR_PATH, "expected_differences", f"{letter}{year}-taxdiffs-expect.csv"
|
154
|
+
)
|
155
|
+
if os.path.isfile(expected_file_name):
|
156
|
+
expect_df = pd.read_csv(expected_file_name, index_col=0)
|
157
|
+
print(actual_df.eq(expect_df))
|
158
|
+
test_passed = np.allclose(
|
159
|
+
actual_df[["# of differing records", "max_diff"]].values,
|
160
|
+
expect_df[["# of differing records", "max_diff"]].values
|
161
|
+
)
|
162
|
+
|
163
|
+
print(
|
164
|
+
"Above, True values mean the element is the same between the ACTUAL and EXPECT dataframes. "
|
165
|
+
+ "(EXPECT files are used for debugging purposes.)"
|
166
|
+
)
|
167
|
+
else:
|
168
|
+
print("This EXPECT file doesn't exist.")
|
169
|
+
|
170
|
+
# (4) Write the created df to *.taxdiffs-actual
|
171
|
+
actual_df.to_csv(
|
172
|
+
os.path.join(
|
173
|
+
CUR_PATH,
|
174
|
+
"actual_differences",
|
175
|
+
f"{letter}{year}-taxdiffs-actual.csv",
|
176
|
+
)
|
177
|
+
)
|
178
|
+
|
179
|
+
return test_passed
|
180
|
+
|
181
|
+
|
182
|
+
if __name__ == "__main__":
|
183
|
+
sys.exit(main())
|
@@ -0,0 +1,161 @@
|
|
1
|
+
"""
|
2
|
+
Translates TAXSIM-35 input file to Tax-Calculator tc input file.
|
3
|
+
"""
|
4
|
+
|
5
|
+
# CODING-STYLE CHECKS:
|
6
|
+
# pycodestyle prepare_tc_input.py
|
7
|
+
# pylint --disable=locally-disabled prepare_tc_input.py
|
8
|
+
|
9
|
+
import argparse
|
10
|
+
import os
|
11
|
+
import sys
|
12
|
+
import numpy as np
|
13
|
+
import pandas as pd
|
14
|
+
|
15
|
+
|
16
|
+
TAXSIM_TC_MAP = {
|
17
|
+
"taxsimid": "RECID",
|
18
|
+
"year": "FLPDYR",
|
19
|
+
# 'state': # no Tax-Calculator use of TAXSIM variable 3, state code
|
20
|
+
# 'mstat', # Tax-Calculator MARS differs from TAXSIM mstat
|
21
|
+
"page": "age_head",
|
22
|
+
"sage": "age_spouse",
|
23
|
+
# 'depx': "", # no Tax-Calculator variable for total number of dependents
|
24
|
+
"dep13": "nu13",
|
25
|
+
"dep17": "nu18",
|
26
|
+
# 'dep18': "n24", #"f2441", # no direct Tax-Calculator use of number EIC qualified dependents
|
27
|
+
"pwages": "e00200p",
|
28
|
+
"swages": "e00200s",
|
29
|
+
"psemp": "e00900p",
|
30
|
+
"ssemp": "e00900s",
|
31
|
+
"dividends": "e00650",
|
32
|
+
"intrec": "e00300",
|
33
|
+
"stcg": "p22250",
|
34
|
+
"ltcg": "p23250",
|
35
|
+
"otherprop": "e02000",
|
36
|
+
"nonprop": "e00800",
|
37
|
+
"pensions": "e01700",
|
38
|
+
"gssi": "e02400",
|
39
|
+
# 'ui': 'e02300', # For TAXSIM-35, UI is separated between primary and secondary filers
|
40
|
+
# 'transfers': # no Tax-Calculator use of TAXSIM variable 22, non-taxable transfers
|
41
|
+
# 'rentpaid' # no Tax-Calculator use of TAXSIM variable 23, rent paid
|
42
|
+
"proptax": "e18500",
|
43
|
+
"otheritem": "e18400",
|
44
|
+
"childcare": "e32800",
|
45
|
+
"mortgage": "e19200",
|
46
|
+
"scorp": "e26270",
|
47
|
+
# 'pbusinc': 'e00900p', # Not perfect match for this in Tax-Calculator -- will add to e00900s below
|
48
|
+
# 'pprofinc': # no direct analog in Tax-Calculator
|
49
|
+
# 'sbusinc': 'e00900s', # Not perfect match for this in Tax-Calculator -- will add to e00900s below
|
50
|
+
# 'sprofinc':# no direct analog in Tax-Calculator
|
51
|
+
}
|
52
|
+
|
53
|
+
|
54
|
+
def main(file_in_name, file_out_name):
|
55
|
+
"""
|
56
|
+
Translates TAXSIM-35 input file into a Tax-Calculator CSV-formatted
|
57
|
+
tc input file. Any pre-existing OUTPUT file contents are overwritten.
|
58
|
+
For details on Internet TAXSIM version 32 INPUT format, go to
|
59
|
+
https://users.nber.org/~taxsim/taxsim35/
|
60
|
+
|
61
|
+
Args:
|
62
|
+
file_in_name (string): name of input file to run taxcalc with
|
63
|
+
file_out_name (string): name of file to save taxcalc output to
|
64
|
+
|
65
|
+
Returns:
|
66
|
+
None
|
67
|
+
"""
|
68
|
+
print("File in and out names: ", file_in_name, file_out_name)
|
69
|
+
# check INPUT filename
|
70
|
+
if not os.path.isfile(file_in_name):
|
71
|
+
emsg = "INPUT file named {} does not exist".format(file_in_name)
|
72
|
+
sys.stderr.write("ERROR: {}\n".format(emsg))
|
73
|
+
assert False
|
74
|
+
# check OUTPUT filename
|
75
|
+
if file_out_name == "":
|
76
|
+
sys.stderr.write("ERROR: must specify OUTPUT file name\n")
|
77
|
+
assert False
|
78
|
+
if os.path.isfile(file_out_name):
|
79
|
+
os.remove(file_out_name)
|
80
|
+
# read TAXSIM-35 INPUT file into a pandas DataFrame
|
81
|
+
ivar = pd.read_csv(file_in_name, header=0, index_col=False)
|
82
|
+
# Drop 'idtl' – used to generate detailed output
|
83
|
+
ivar.drop(columns=["idtl"], inplace=True)
|
84
|
+
# translate INPUT variables into OUTPUT variables
|
85
|
+
invar = translate(ivar)
|
86
|
+
# write OUTPUT file containing Tax-Calculator input variables
|
87
|
+
invar.to_csv(file_out_name, index=False)
|
88
|
+
# return no-error exit code
|
89
|
+
return 0
|
90
|
+
|
91
|
+
|
92
|
+
# end of main function code
|
93
|
+
|
94
|
+
|
95
|
+
def translate(ivar):
|
96
|
+
"""
|
97
|
+
Translate TAXSIM-35 input variables into Tax-Calculator input variables.
|
98
|
+
Both ivar and returned invar are pandas DataFrame objects.
|
99
|
+
"""
|
100
|
+
assert isinstance(ivar, pd.DataFrame)
|
101
|
+
# Rename variables to be consistent with Tax-Calculator naming conventions
|
102
|
+
invar = ivar.rename(TAXSIM_TC_MAP, axis=1)
|
103
|
+
invar["n24"] = ivar["dep17"]
|
104
|
+
# Create variables for Tax-Calculator that aren't directly represented in TAXSIM
|
105
|
+
invar["e02000"] += invar[
|
106
|
+
"e26270"
|
107
|
+
] # add active scorp income to "otherprop" income from taxsim
|
108
|
+
mstat = ivar["mstat"]
|
109
|
+
assert np.all(np.logical_or(mstat == 1, mstat == 2))
|
110
|
+
num_deps = ivar["depx"]
|
111
|
+
mars = np.where(mstat == 1, np.where(num_deps > 0, 4, 1), 2)
|
112
|
+
assert np.all(
|
113
|
+
np.logical_or(mars == 1, np.logical_or(mars == 2, mars == 4))
|
114
|
+
)
|
115
|
+
invar["MARS"] = mars
|
116
|
+
num_eitc_qualified_kids = ivar["dep18"]
|
117
|
+
invar["f2441"] = invar["nu13"]
|
118
|
+
invar["EIC"] = np.minimum(num_eitc_qualified_kids, 3)
|
119
|
+
num_taxpayers = np.where(mars == 2, 2, 1)
|
120
|
+
invar["XTOT"] = num_taxpayers + num_deps
|
121
|
+
invar["e00200"] = invar["e00200p"] + invar["e00200s"]
|
122
|
+
invar["e00900p"] += invar["pbusinc"]
|
123
|
+
invar["e00900s"] += invar[
|
124
|
+
"sbusinc"
|
125
|
+
] # NB: will need to check this later because in TAXSIM, the e00900 does not include QBI, but businc does...
|
126
|
+
invar["e00900"] = invar["e00900p"] + invar["e00900s"]
|
127
|
+
invar["e00600"] = invar["e00650"]
|
128
|
+
invar["e01500"] = invar["e01700"]
|
129
|
+
invar["e02300"] = invar["pui"] + invar["sui"]
|
130
|
+
# variables for QBID calculation
|
131
|
+
invar["PT_SSTB_income"] = (
|
132
|
+
0 # np.where(invar['pprofinc'] + invar['sprofinc'] > 0, 1, 0)
|
133
|
+
)
|
134
|
+
invar["PT_SSTB_income"] = (
|
135
|
+
0 # np.where(invar['e26270'] > 0, 1, invar['PT_SSTB_income'])
|
136
|
+
)
|
137
|
+
|
138
|
+
# Drop TAXSIM variables not used in Tax-Calculator
|
139
|
+
invar.drop(
|
140
|
+
columns=[
|
141
|
+
"state",
|
142
|
+
"mstat",
|
143
|
+
"depx",
|
144
|
+
# "dep18",
|
145
|
+
"transfers",
|
146
|
+
"rentpaid",
|
147
|
+
"pprofinc",
|
148
|
+
"pbusinc",
|
149
|
+
"sbusinc",
|
150
|
+
"sprofinc",
|
151
|
+
"pui",
|
152
|
+
"sui",
|
153
|
+
],
|
154
|
+
inplace=True,
|
155
|
+
)
|
156
|
+
|
157
|
+
return invar
|
158
|
+
|
159
|
+
|
160
|
+
if __name__ == "__main__":
|
161
|
+
sys.exit(main())
|
@@ -0,0 +1,140 @@
|
|
1
|
+
"""
|
2
|
+
Translates tc --dump output file into file formatted like TAXSIM-35 output.
|
3
|
+
"""
|
4
|
+
|
5
|
+
# CODING-STYLE CHECKS:
|
6
|
+
# pycodestyle process_tc_output.py
|
7
|
+
# pylint --disable=locally-disabled process_tc_output.py
|
8
|
+
|
9
|
+
import argparse
|
10
|
+
import os
|
11
|
+
import sys
|
12
|
+
import pandas as pd
|
13
|
+
|
14
|
+
|
15
|
+
def main(input_file_name, output_file_name):
|
16
|
+
"""
|
17
|
+
Translates tc --dump output file into an output file that is
|
18
|
+
formatted like the first 28 variables in TAXSIM-35 output. The INPUT
|
19
|
+
file contains the output generated by running tc with the --dump
|
20
|
+
option. Any pre-existing OUTPUT file contents will be overwritten.
|
21
|
+
For details on Internet TAXSIM version 35 OUTPUT format, go to
|
22
|
+
https://users.nber.org/~taxsim/taxsim35/
|
23
|
+
|
24
|
+
Args:
|
25
|
+
input_file_name (string): name of file with taxcalc formatted output
|
26
|
+
output_file_name (string): name of file with taxsim formatted output
|
27
|
+
|
28
|
+
Returns:
|
29
|
+
None
|
30
|
+
"""
|
31
|
+
# check INPUT filename
|
32
|
+
if input_file_name == "":
|
33
|
+
sys.stderr.write("ERROR: must specify INPUT file name\n")
|
34
|
+
sys.stderr.write("USAGE: {}\n".format(usage_str))
|
35
|
+
assert False
|
36
|
+
if not os.path.isfile(input_file_name):
|
37
|
+
emsg = "INPUT file named {} does not exist".format(args.INPUT)
|
38
|
+
sys.stderr.write("ERROR: {}\n".format(emsg))
|
39
|
+
assert False
|
40
|
+
# check OUTPUT filename
|
41
|
+
if output_file_name == "":
|
42
|
+
sys.stderr.write("ERROR: must specify OUTPUT file name\n")
|
43
|
+
sys.stderr.write("USAGE: {}\n".format(usage_str))
|
44
|
+
assert False
|
45
|
+
if os.path.isfile(output_file_name):
|
46
|
+
os.remove(output_file_name)
|
47
|
+
# read INPUT file into a pandas DataFrame
|
48
|
+
tcvar = pd.read_csv(input_file_name)
|
49
|
+
# write OUTPUT file using the pandas DataFrame
|
50
|
+
write_taxsim_formatted_output(output_file_name, tcvar)
|
51
|
+
# return no-error exit code
|
52
|
+
return 0
|
53
|
+
|
54
|
+
|
55
|
+
# end of main function code
|
56
|
+
|
57
|
+
|
58
|
+
def write_taxsim_formatted_output(filename, tcvar):
|
59
|
+
"""
|
60
|
+
Write contents of tcvar pandas DataFrame to filename using
|
61
|
+
Internet-TAXSIM 9.3 output format containing 28 variables.
|
62
|
+
"""
|
63
|
+
assert isinstance(tcvar, pd.DataFrame)
|
64
|
+
# with open(filename, 'w') as output_file:
|
65
|
+
# for idx in range(0, len(tcvar.index)):
|
66
|
+
# odict4idx = extract_output(tcvar.xs(idx))
|
67
|
+
# outline = construct_output_line(odict4idx)
|
68
|
+
# output_file.write(outline)
|
69
|
+
tcvar["state"] = 0 # state code is always zero
|
70
|
+
tcvar["statetax"] = 0.0 # no state income tax calculation
|
71
|
+
tcvar["mtr_state"] = 0.0 # no state income tax calculation
|
72
|
+
tcvar["zero_bracket_amount"] = (
|
73
|
+
0.0 # always set zero-bracket amount to zero
|
74
|
+
)
|
75
|
+
pre_phase_out_pe = tcvar["pre_c04600"].values
|
76
|
+
post_phase_out_pe = tcvar["c04600"].values
|
77
|
+
phased_out_pe = pre_phase_out_pe - post_phase_out_pe
|
78
|
+
tcvar["post_phase_out_pe"] = (
|
79
|
+
post_phase_out_pe # post-phase-out personal exemption
|
80
|
+
)
|
81
|
+
tcvar["phased_out_pe"] = (
|
82
|
+
phased_out_pe # personal exemption that is phased out
|
83
|
+
)
|
84
|
+
tcvar["exemption_surtax"] = 0.0 # always set exemption surtax to zero
|
85
|
+
tcvar["gen_tax_credit"] = 0.0 # always set general tax credit to zero
|
86
|
+
tcvar["non_refundable_child_odep_credit"] = (
|
87
|
+
tcvar["c07220"] + tcvar["odc"] + tcvar["ctc_new"]
|
88
|
+
) # non-refundable child+odep credit
|
89
|
+
tcvar["refundable_CDCC"] = tcvar["CDCC_refund"] # refundable CDCC
|
90
|
+
tcvar["amt_liability"] = tcvar["c09600"] # federal AMT liability
|
91
|
+
# var28 from TAXSIM-35 is federal income tax before credits; the Tax-Calculator
|
92
|
+
# tcvar['c05800'] is this concept but includes AMT liability
|
93
|
+
# while Internet-TAXSIM tcvar[28] explicitly excludes AMT liability, so
|
94
|
+
# we have the following:
|
95
|
+
tcvar["iitax_before_credits_ex_AMT"] = (
|
96
|
+
tcvar["c05800"] - tcvar["amt_liability"]
|
97
|
+
)
|
98
|
+
tcvar = tcvar[
|
99
|
+
[
|
100
|
+
"RECID",
|
101
|
+
"FLPDYR",
|
102
|
+
"state",
|
103
|
+
"iitax",
|
104
|
+
"statetax",
|
105
|
+
"payrolltax",
|
106
|
+
"mtr_inctax",
|
107
|
+
"mtr_state",
|
108
|
+
# 'mtr_paytax',
|
109
|
+
"c00100",
|
110
|
+
"e02300",
|
111
|
+
"c02500",
|
112
|
+
# 'zero_bracket_amount',
|
113
|
+
"post_phase_out_pe",
|
114
|
+
"phased_out_pe",
|
115
|
+
"c21040",
|
116
|
+
"c04470",
|
117
|
+
"c04800",
|
118
|
+
"taxbc",
|
119
|
+
"exemption_surtax",
|
120
|
+
"gen_tax_credit",
|
121
|
+
"non_refundable_child_odep_credit",
|
122
|
+
"c11070",
|
123
|
+
"c07180",
|
124
|
+
"refundable_CDCC",
|
125
|
+
"eitc",
|
126
|
+
"c62100",
|
127
|
+
"amt_liability",
|
128
|
+
"iitax_before_credits_ex_AMT",
|
129
|
+
"recovery_rebate_credit",
|
130
|
+
]
|
131
|
+
]
|
132
|
+
# better mapping of to how TAXSIM-35 handles refundable credits in 2021
|
133
|
+
tcvar.loc[tcvar["FLPDYR"] == 2021, "c11070"] = tcvar.loc[
|
134
|
+
tcvar["FLPDYR"] == 2021, "non_refundable_child_odep_credit"
|
135
|
+
]
|
136
|
+
tcvar.loc[tcvar["FLPDYR"] == 2021, "c07180"] = tcvar.loc[
|
137
|
+
tcvar["FLPDYR"] == 2021, "refundable_CDCC"
|
138
|
+
]
|
139
|
+
tcvar.round(decimals=2)
|
140
|
+
tcvar.to_csv(filename)
|
@@ -0,0 +1,49 @@
|
|
1
|
+
// JSON "reform" file that specifies changes in current-law policy that
|
2
|
+
// are required to make Tax-Calculator work like TAXSIM-35.
|
3
|
+
//
|
4
|
+
// (1) AMT_child_em_c_age = 24 (rather than 18)
|
5
|
+
// Whether to set this parameter to 18 or 24 is arbitary because
|
6
|
+
// neither model has enough information to apply correctly the child
|
7
|
+
// AMT exemption rules. Information on full-time student status and
|
8
|
+
// whether taxpayers provide more than half of their support are required
|
9
|
+
// to apply the rules correctly. Tax-Calculator makes the arbitrary
|
10
|
+
// assumption that only those under 18 are required to use the child
|
11
|
+
// AMT exemption rules, while TAXSIM-27 makes the arbitrary assumption
|
12
|
+
// that all those under 24 are required to use the child AMT exemption.
|
13
|
+
// (This change was introduced for assumption set b and higher.)
|
14
|
+
//
|
15
|
+
// (2) EITC_excess_InvestIncome_rt = 1.0 (rather than 9e99)
|
16
|
+
// The rate at which the EITC amount is reduced per dollar of investment
|
17
|
+
// income in excess of the EITC investment income ceiling is infinity under
|
18
|
+
// current law (that is, any investment income in excess of the ceiling
|
19
|
+
// causes EITC ineligibility). However, TAXSIM-27 assumes it is one, so
|
20
|
+
// that the EITC amount is reduced a dollar for each dollar of excess
|
21
|
+
// investment income. This difference in the parameter value leads to
|
22
|
+
// many EITC differences in the randomly-generated validation samples,
|
23
|
+
// with some of the differences being in the thousands of dollars. This
|
24
|
+
// non-current-law assumption in TAXSIM-27 is presumably made to reduce
|
25
|
+
// the magnitude of model-calculated marginal tax rates with respect to
|
26
|
+
// investment income in cases where a marginal increase in investment
|
27
|
+
// income takes a filing unit above the ceiling.
|
28
|
+
|
29
|
+
// (3) ALD_AlimonyReceived_hc = 1.0 (rather than 0)
|
30
|
+
// TAXSIM35 nonproperty income is mapped into AlimonyRecieved
|
31
|
+
// which had its haircut change from 1.0 to 0.0, a change that
|
32
|
+
// TAXSIM35 has not implemented for good reason given this:
|
33
|
+
// IRS: 'Beginning Jan. 1, 2019, alimony or separate
|
34
|
+
// maintenance payments are not deductible from the
|
35
|
+
// income of the payer spouse, or includable in the
|
36
|
+
// income of the receiving spouse, if made under a
|
37
|
+
// divorce or separation agreement executed after
|
38
|
+
// Dec. 31, 2018.
|
39
|
+
|
40
|
+
// (4) PT_qbid_limit_switch = false implies TAXSIM35-like QBI deduction logic.
|
41
|
+
{
|
42
|
+
"AMT_child_em_c_age": {"2013": 24},
|
43
|
+
|
44
|
+
"EITC_excess_InvestIncome_rt": {"2013": 1.0},
|
45
|
+
|
46
|
+
"ALD_AlimonyReceived_hc": {"2019": 1.0},
|
47
|
+
|
48
|
+
"PT_qbid_limit_switch": {"2018": false}
|
49
|
+
}
|