Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

initial implementation of charitable giving elasticity #1246

Merged
merged 6 commits into from
Mar 20, 2017

Conversation

MattHJensen
Copy link
Contributor

This is part 1 of a series of changes that will resolve #1237.

This PR implements charitable giving elasticities that vary by itemizing status. Sample reforms and usage are below.

A follow on PR will allow the elasticities to vary by income.

The elasticity for non-itemizers won't be valuable until @jjbergdo or @GoFroggyRun finish their imputations of charitable giving for non-itemizers.

cc @martinholmer @codykallen @jjbergdo

Testing charitable contribution behavioral features

Import taxcalc package and other useful packages

import sys
sys.path.append("../../")
from taxcalc import *

Create Plan X and Plan Y Policy objects containing current law policy and then implement reforms

# The baseline includes AMT repeal. 
p_xx = Policy()
reform_xx = {
    2016: {
          '_AMT_rt1': [0],
          '_AMT_rt2': [0], 
    }
}
p_xx.implement_reform(reform_xx)

# The reform expands the second tax bracket
# (and repeals AMT to match the baseline)

p_yy = Policy()
reform_yy = {
    2016: {
        '_AMT_rt1': [0],
        '_AMT_rt2': [0], 
        '_ID_Charity_hc': [.5]

    }
}
p_yy.implement_reform(reform_yy)
bhv = Behavior()

Create calculator objects with default tax data and advance the calculator to 2016

c_xx = Calculator(policy=p_xx, records=Records("../../puf.csv"))
c_xx.advance_to_year(2020)
c_yy = Calculator(policy=p_yy, records=Records("../../puf.csv"), behavior = bhv)
c_yy.advance_to_year(2020)
You loaded data for 2009.
Tax-Calculator startup automatically extrapolated your data to 2013.
You loaded data for 2009.
Tax-Calculator startup automatically extrapolated your data to 2013.

Implement Behavior

# Itemizers
reform_be_item = {2020: {'_BE_charity_itemizers': [.5]}}
bhv.update_behavior(reform_be_item)
c_yy_beh_item = Behavior.response(c_xx, c_yy)

# Non-itemizers
reform_be_no_item = {2020: {'_BE_charity_non_itemizers': [.5]}}
bhv.update_behavior(reform_be_no_item)
c_yy_beh_no_item = Behavior.response(c_xx, c_yy)

Calculate taxes under the baseline and under the reform.

c_xx.calc_all()
c_yy.calc_all()
c_yy_beh_item.calc_all()
c_yy_beh_no_item.calc_all()

Calculate the change in combined tax revenue

No behavior

((c_yy.records._combined - c_xx.records._combined)*c_xx.records.s006).sum()/1000000000
29.780937267036911

Itemizer behavior

((c_yy_beh_item.records._combined - c_xx.records._combined)*c_xx.records.s006).sum()/1000000000
31.071111883705189

Non-itemizer behavior

((c_yy_beh_no_item.records._combined - c_xx.records._combined)*c_xx.records.s006).sum()/1000000000
29.780937267036911

Calculate cash charity before and after reform.

No behavior

((c_yy.records.e19800)*c_yy.records.s006).sum()/1000000000
202.17375890856968

Itemizer behavior

((c_yy_beh_item.records.e19800)*c_xx.records.s006).sum()/1000000000
193.40411585066309

Non-itemizer behavior

((c_yy_beh_no_item.records.e19800)*c_xx.records.s006).sum()/1000000000
201.4100883665042

One might expect that non-itemizer behavior would not affect results since we don't yet have data on charitable contributions for non-itemizers. However, the reason there is a slight change is because we choose which elasticity to apply to taxpayers based on their itemizing status after the reform rather than before the reform.

The total difference caused by non-itemizer behavior is:

((c_yy_beh_no_item.records.e19800 - c_yy.records.e19800)*c_xx.records.s006).sum()/1000000000
-0.7636705420654728

The difference for taxpayers who itemized before the reform accounts for the total.

((c_yy_beh_no_item.records.e19800 - c_yy.records.e19800)*c_xx.records.s006)[c_xx.records.c04470 > c_xx.records._standard].sum()/1000000000
-0.76367054206547258

There is no difference for taxpayers who took the standard deduction before the reform:

((c_yy_beh_no_item.records.e19800 - c_yy.records.e19800)*c_xx.records.s006)[c_xx.records.c04470 < c_xx.records._standard].sum()/1000000000
0.0

@codecov-io
Copy link

codecov-io commented Mar 15, 2017

Codecov Report

Merging #1246 into master will increase coverage by 0.4%.
The diff coverage is 100%.

@@            Coverage Diff            @@
##           master    #1246     +/-   ##
=========================================
+ Coverage   99.26%   99.67%   +0.4%     
=========================================
  Files          38       38             
  Lines        2705     2729     +24     
=========================================
+ Hits         2685     2720     +35     
+ Misses         20        9     -11
Impacted Files Coverage Δ
taxcalc/calculate.py 100% <ø> (ø)
taxcalc/behavior.py 100% <100%> (ø)
taxcalc/records.py 99.11% <0%> (ø)
taxcalc/growfactors.py 98.61% <0%> (ø)
taxcalc/utils.py 99.3% <0%> (+1.05%)
taxcalc/parameters.py 99.15% <0%> (+2.06%)

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update a963067...6b02cc9. Read the comment docs.

@codykallen
Copy link
Contributor

@MattHJensen, this is a good new capability. However, I am concerned about your implementation of the elasticity with respect to the MTR on charitable giving. Your formula:

charity_mtr_pch = (1. - charity_mtr_y) / (1. - charity_mtr_x) - 1

I believe this is incorrect. The standard approach for charitable giving is that the elasticity is with respect to the after-tax price of giving. If memory serves, the median estimate for this elasticity is approximately -1. Since the MTR on charitable giving is negative (as an additional dollar of giving reduces an itemizer's taxes), the correct formula should be:

charity_price_pch = (1. + charity_mtr_y) / (1. + charity_mtr_x) - 1

To put this in context, suppose that in the baseline, charity_mtr_x = 0.35. Suppose that the reform eliminates the charitable contribution deduction, so charity_mtr_y = 0. Then the after-tax price of charitable giving rises from 0.65 to 1, a 53.8% increase. With an elasticity of -1, charitable giving falls by 53.8%.

On an additional note, I think the behavioral response should apply to non-cash contributions (e20100) in addition to cash contributions (e19800).

@feenberg
Copy link
Contributor

feenberg commented Mar 15, 2017 via email

@codykallen
Copy link
Contributor

@feenberg, thank you for the catching my mistake. My earlier comment should say:

To put this in context, suppose that in the baseline, charity_mtr_x = -0.35.

@MattHJensen
Copy link
Contributor Author

MattHJensen commented Mar 15, 2017

@codykallen, thanks for the correction/suggestion:

  • the correct formula should be: charity_price_pch = (1. + charity_mtr_y) / (1. + charity_mtr_x) - 1
  • I think the behavioral response should apply to non-cash contributions (e20100) in addition to cash contributions (e19800).

One down, one to go.

@MattHJensen
Copy link
Contributor Author

I think the behavioral response should apply to non-cash contributions (e20100) in addition to cash contributions (e19800).

Thanks for the suggestion @codykallen. The latest commit implements this. Could you take a look?

Note that the same elasticities are used for both types of contributions. We could also use separate elasticities if they are typically estimated separately in the literature.

@feenberg, @jjbergdo, @martinholmer

@MattHJensen
Copy link
Contributor Author

Here's an updated notebook:

Testing charitable contribution behavioral features

Import taxcalc package and other useful packages

import sys
sys.path.append("../../")
from taxcalc import *

Create Plan X and Plan Y Policy objects containing current law policy and then implement reforms

# The baseline includes AMT repeal. 
p_xx = Policy()
reform_xx = {
    2016: {
          '_AMT_rt1': [0],
          '_AMT_rt2': [0], 
    }
}
p_xx.implement_reform(reform_xx)

# The reform expands the second tax bracket
# (and repeals AMT to match the baseline)

p_yy = Policy()
reform_yy = {
    2016: {
        '_AMT_rt1': [0],
        '_AMT_rt2': [0], 
        '_ID_Charity_hc': [.5]

    }
}
p_yy.implement_reform(reform_yy)
bhv = Behavior()

Create calculator objects with default tax data and advance the calculator to 2016

c_xx = Calculator(policy=p_xx, records=Records("../../puf.csv"))
c_xx.advance_to_year(2020)
c_yy = Calculator(policy=p_yy, records=Records("../../puf.csv"), behavior = bhv)
c_yy.advance_to_year(2020)
You loaded data for 2009.
Tax-Calculator startup automatically extrapolated your data to 2013.
You loaded data for 2009.
Tax-Calculator startup automatically extrapolated your data to 2013.

Implement Behavior

# Itemizers
reform_be_item = {2020: {'_BE_charity_itemizers': [-1]}}
bhv.update_behavior(reform_be_item)
c_yy_beh_item = Behavior.response(c_xx, c_yy)

# Non-itemizers
reform_be_no_item = {2020: {'_BE_charity_non_itemizers': [-1]}}
bhv.update_behavior(reform_be_no_item)
c_yy_beh_no_item = Behavior.response(c_xx, c_yy)

Calculate taxes under the baseline and under the reform.

c_xx.calc_all()
c_yy.calc_all()
c_yy_beh_item.calc_all()
c_yy_beh_no_item.calc_all()

Calculate the change in combined tax revenue

No behavior

((c_yy.records._combined - c_xx.records._combined)*c_xx.records.s006).sum()/1000000000
29.780937267036911

Itemizer behavior

((c_yy_beh_item.records._combined - c_xx.records._combined)*c_xx.records.s006).sum()/1000000000
35.783363792906485

Non-itemizer behavior

((c_yy_beh_no_item.records._combined - c_xx.records._combined)*c_xx.records.s006).sum()/1000000000
29.780937267036911

Calculate charity before and after reform.

def wt_comb_char(self):
    weighted_combined_charity = (self.records.e19800 + self.records.e20100)*self.records.s006
    return weighted_combined_charity

No behavior

comb_char_no_beh = wt_comb_char(c_yy)
comb_char_no_beh.sum()/1000000000
246.78351645568389

Itemizer behavior only

comb_char_item_beh = wt_comb_char(c_yy_beh_item)
comb_char_item_beh.sum()/1000000000
207.36242198977411

Non-itemizer behavior only

comb_char_no_item_beh = wt_comb_char(c_yy_beh_no_item)
comb_char_no_item_beh.sum()/1000000000
244.17007689481684

One might expect that non-itemizer behavior would not affect results since we don't yet have data on charitable contributions for non-itemizers. However, the reason there is a slight change is because we choose which elasticity to apply to taxpayers based on their itemizing status after the reform rather than before the reform.

The total difference caused by non-itemizer behavior is:

(comb_char_no_item_beh - comb_char_no_beh).sum()/1000000000
-2.6134395608670378

The difference for taxpayers who itemized before the reform accounts for the total.

(comb_char_no_item_beh - comb_char_no_beh)[c_xx.records.c04470 > c_xx.records._standard].sum()/1000000000
-2.6134395608670387

There is no difference for taxpayers who took the standard deduction before the reform:

(comb_char_no_item_beh - comb_char_no_beh)[c_xx.records.c04470 < c_xx.records._standard].sum()/1000000000
0.0

@codykallen
Copy link
Contributor

@MattHJensen, thanks for making these changes. This looks much better.

I hate to nitpick, but I have one remaining concern regarding the naming convention. Using the formula I mentioned earlier, you calculate c_charity_mtr_pch and `nc_charity_mtr_pch'. However, these calculations are for the percent change in the after-tax price of giving, not the percent change in the MTR.

@MattHJensen
Copy link
Contributor Author

I hate to nitpick, but I have one remaining concern regarding the naming convention. Using the formula I mentioned earlier, you calculate c_charity_mtr_pch and `nc_charity_mtr_pch'. However, these calculations are for the percent change in the after-tax price of giving, not the percent change in the MTR.

@codykallen, thanks for the close review! The variable naming is corrected in the latest commit.

@codykallen
Copy link
Contributor

Thanks, @MattHJensen. Looks good to me!

@MattHJensen
Copy link
Contributor Author

I plan to merge this evening if there are no further comments.

@MattHJensen MattHJensen merged commit 4af6bd4 into PSLmodels:master Mar 20, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Tax Elasticities On Giving
4 participants