def test_quantity_response(): """ Test quantity_response function. """ quantity = np.array([1.0] * 10) res = quantity_response(quantity) assert np.allclose(res, np.zeros(quantity.shape)) one = np.ones(quantity.shape) res = quantity_response(quantity, price_elasticity=-0.2, aftertax_price1=one, aftertax_price2=one, income_elasticity=0.1, aftertax_income1=one, aftertax_income2=(one + one)) assert not np.allclose(res, np.zeros(quantity.shape))
def test_labor_response(): """ Test that labor_response produces the same result as quantity_response where mtr* = 1 - aftertax_price*, using default earnings/quantity=1. """ res_lr = labor_response(substitution_eti=1, mtr1=0.4, mtr2=0.5) res_qr = quantity_response(price_elasticity=1, aftertax_price1=0.6, aftertax_price2=0.5) assert np.allclose(res_lr, res_qr)
price_elasticity = [-0.1, -0.4] income_elasticity = [0.1, 0.1] print('\nResponse in Charitable Giving by Earnings Group') results = '{:18s}\t{:8.3f}\t{:8.3f}\t{:8.2f}' colhead = '{:18s}\t{:>8s}\t{:>8s}\t{:>8s}' print(colhead.format('Earnings Group', 'Num(#M)', 'Resp($B)', 'Resp(%)')) tot_funits = 0. tot_response = 0. tot_baseline = 0. idx = 0 for grp_interval, grp in gbydf: funits = grp['s006'].sum() * 1e-6 tot_funits += funits response = behresp.quantity_response(grp['e19800'], price_elasticity[idx], grp['price1'], grp['price2'], income_elasticity[idx], grp['atinc1'], grp['atinc2']) grp_response = (response * grp['s006']).sum() * 1e-9 tot_response += grp_response grp_baseline = (grp['e19800'] * grp['s006']).sum() * 1e-9 tot_baseline += grp_baseline pct_response = 100. * grp_response / grp_baseline glabel = '[{:.8g}, {:.8g})'.format(grp_interval.left, grp_interval.right) print(results.format(glabel, funits, grp_response, pct_response)) idx += 1 pct_response = 100. * tot_response / tot_baseline print(results.format('ALL', tot_funits, tot_response, pct_response))
vdf['price1'] = 1.0 + mtr1 vdf['price2'] = 1.0 + mtr2 vdf['atinc1'] = calc1.array('aftertax_income') vdf['atinc2'] = calc2.array('aftertax_income') # group filing units into earnings groups with different response elasticities # (note earnings groups are just an example based on no empirical results) EARNINGS_BINS = [-9e99, 50e3, 9e99] # Two groups: below and above $50,000. vdf['table_row'] = pd.cut(vdf.e00200, EARNINGS_BINS, right=False).astype(str) vdf['price_elasticity'] = np.where(vdf.e00200 < EARNINGS_BINS[1], -0.1, -0.4) vdf['income_elasticity'] = 0.1 # Calculate response based on features of each filing unit. vdf['response'] = behresp.quantity_response(vdf.e19800, vdf.price_elasticity, vdf.price1, vdf.price2, vdf.income_elasticity, vdf.atinc1, vdf.atinc2) # Add weighted totals. # Can also use microdf as mdf.add_weighted_totals(vdf, ['response', 'e19800']) vdf['e19800_b'] = vdf.s006 * vdf.e19800 / 1e9 vdf['response_b'] = vdf.s006 * vdf.response / 1e9 vdf['funits_m'] = vdf.s006 / 1e6 SUM_VARS = ['funits_m', 'e19800_b', 'response_b'] # Sum weighted total columns for each income group. grouped = vdf.groupby('table_row')[SUM_VARS].sum() # Add a total row and make the index a column for printing. grouped.loc['TOTAL'] = grouped.sum() grouped.reset_index(inplace=True)