#!/usr/bin/env python # coding: utf-8 # # Unemployment insurance vs. UBI # # Compare the poverty and distributional impacts of giving \$600 per unemployment insurance beneficiary--as proposed in the latest CARES Act--to using the same amount for a UBI. # # Data: 2018 ASEC # # ## Setup # In[1]: import pandas as pd import numpy as np import microdf as mdf import matplotlib.pyplot as plt import matplotlib as mpl import os # ## Load data # In[2]: ASEC_F = '~/data/asec/2019/pppub19.csv' SPM_COLS = ['povthreshold', 'resources', 'poor', 'numper', 'numkids', 'numadults', 'id', 'weight'] OTHER_COLS = ['A_AGE', 'MARSUPWT', 'UC_VAL'] cols = ['SPM_' + i.upper() for i in SPM_COLS] + OTHER_COLS raw = pd.read_csv(ASEC_F, usecols=cols) # ## Preprocess # In[3]: df = raw.copy(deep=True) # In[4]: df.columns = map(str.lower, df.columns) # Add true weight by dividing by 100. # In[5]: df['w'] = df.marsupwt / 100. df['spm_w'] = df.spm_weight / 100. # In[6]: mdf.weighted_sum(df, 'uc_val', 'w') / 1e9 # ## Simulate # In[7]: UI_BONUS = 600 * 17 # In[8]: df['ui_bonus'] = np.where(df.uc_val > 0, UI_BONUS, 0) # In[9]: spmu = df.groupby('spm_id')[['ui_bonus']].sum() spmu_raw = df[['spm_resources', 'spm_povthreshold', 'spm_id', 'spm_numper', 'spm_w']].drop_duplicates().set_index('spm_id') spmu = spmu.join(spmu_raw) spmu # In[10]: budget = mdf.weighted_sum(spmu, 'ui_bonus', 'spm_w') budget / 1e9 # In[11]: ubi = budget / (spmu.spm_numper * spmu.spm_w).sum() ubi # In[12]: spmu['ubi'] = ubi * spmu.spm_numper # In[13]: mdf.weighted_sum(spmu, 'ubi', 'spm_w') - budget # Add new resource columns and merge back to person level dataset. # In[14]: spmu['spm_resources_ui'] = spmu.spm_resources + spmu.ui_bonus spmu['spm_resources_ubi'] = spmu.spm_resources + spmu.ubi # In[15]: df = df.merge(spmu[['spm_resources_ui', 'spm_resources_ubi']], on='spm_id') # ## Calculate effects # In[16]: df['spm_poor_ui'] = np.where(df.spm_resources_ui < df.spm_povthreshold, 1, 0) df['spm_poor_ubi'] = np.where(df.spm_resources_ubi < df.spm_povthreshold, 1, 0) # In[17]: pov_rate_base = mdf.weighted_mean(df, 'spm_poor', 'w') pov_rate_ui = mdf.weighted_mean(df, 'spm_poor_ui', 'w') pov_rate_ubi = mdf.weighted_mean(df, 'spm_poor_ubi', 'w') # In[18]: (pov_rate_base - pov_rate_ubi) / (pov_rate_base - pov_rate_ui) # Poverty gap. # In[19]: def pov_gap(resource_col): pov_gap = np.maximum(spmu.spm_povthreshold - spmu[resource_col], 0) return (pov_gap * spmu.spm_w).sum() / 1e9 # In[20]: pov_gap_base = pov_gap('spm_resources') pov_gap_ui = pov_gap('spm_resources_ui') pov_gap_ubi = pov_gap('spm_resources_ubi') # In[21]: (pov_gap_base - pov_gap_ubi) / (pov_gap_base - pov_gap_ui) # ## Poverty rate of those on UI # In[22]: def pov_rate(df): return mdf.weighted_mean(df, 'spm_poor', 'w') # In[23]: pov_rate(df[df.uc_val > 0]) # In[24]: pov_rate(df[df.uc_val == 0]) # ## Where in the wage distribution are people who collect UI? # # [Pelosi said:](https://www.cnbc.com/2020/03/25/bernie-sanders-4-gop-senators-threaten-to-hold-up-coronavirus-stimulus-bill.html) # >Please don’t resent our lowest paid workers in America for getting \$600. # In[25]: spmu['pov_ratio'] = spmu.spm_resources / spmu.spm_povthreshold # In[26]: spmu_ui = spmu[spmu.ui_bonus > 0].copy(deep=True) spmu_noui = spmu[spmu.ui_bonus == 0].copy(deep=True) # In[27]: mdf.weighted_median(spmu, 'pov_ratio', 'spm_w') # In[28]: mdf.weighted_median(spmu_ui, 'pov_ratio', 'spm_w') # In[29]: mdf.weighted_median(spmu_noui, 'pov_ratio', 'spm_w') # ### t test # # Highly significant (2nd element is p value). # In[30]: from statsmodels.stats import weightstats # In[31]: weightstats.ttest_ind(spmu_ui.pov_ratio, spmu_noui.pov_ratio, weights=(spmu_ui.spm_w, spmu_noui.spm_w))