def test_save_return_table_write(df, output_type, path): ''' Test of the utils.save_return_table function for case when write to disk ''' utils.save_return_table(df, output_type, path=path) filehandle = open(path) try: assert filehandle.read() is not None except UnicodeDecodeError: from openpyxl import load_workbook wb = load_workbook(filename=path)
def tp_output_dump_table(base_params, base_tpi, reform_params=None, reform_tpi=None, table_format=None, path=None): ''' This function dumps many of the macro time series from the transition path into an output table. Args: base_params (OG-USA Specifications class): baseline parameters object base_tpi (dictionary): TP output from baseline run reform_params (OG-USA Specifications class): reform parameters object reform_tpi (dictionary): TP output from reform run table_format (string): format to return table in: 'csv', 'tex', 'excel', 'json', if None, a DataFrame is returned path (string): path to save table to Returns: table (various): table in DataFrame or string format or `None` if saved to disk ''' T = base_params.T # keep just items of interest for final table vars_to_keep = [ 'Y', 'L', 'G', 'TR', 'B', 'K', 'K_d', 'K_f', 'D', 'D_d', 'D_f', 'r', 'r_gov', 'r_hh', 'w', 'total_tax_revenue', 'business_tax_revenue' ] base_dict = {k: base_tpi[k] for k in vars_to_keep} # update key names base_dict_final = dict( (VAR_LABELS[k] + ': Baseline', v[:T]) for (k, v) in base_dict.items()) # create df table_df = pd.DataFrame.from_dict(base_dict_final) if reform_tpi is not None: assert (base_params.start_year == reform_params.start_year) assert (base_params.T == reform_params.T) reform_dict = {k: reform_tpi[k] for k in vars_to_keep} # update key names reform_dict_final = dict((VAR_LABELS[k] + ': Reform', v[:T]) for (k, v) in reform_dict.items()) df_reform = pd.DataFrame.from_dict(reform_dict_final) # merge dfs table_df = table_df.merge(df_reform, left_index=True, right_index=True) # rename index to year table_df.reset_index(inplace=True) table_df.rename(columns={'index': 'Year'}, inplace=True) # update index to reflect years table_df['Year'] = table_df['Year'] + base_params.start_year table = save_return_table(table_df, table_format, path) return table
def wealth_moments_table(base_ss, base_params, table_format=None, path=None): ''' Creates table with moments of the wealth distribution from the model and SCF data. Args: base_ss (dictionary): SS output from baseline run base_params (OG-USA Specifications class): baseline parameters object table_format (string): format to return table in: 'csv', 'tex', 'excel', 'json', if None, a DataFrame is returned path (string): path to save table to Returns: table (various): table in DataFrame or string format or `None` if saved to disk ''' table_dict = { 'Moment': [ 'Share 0-25%', 'Share 25-50%', 'Share 50-70%', 'Share 70-80%', 'Share 80-90%', 'Share 90-99%', 'Share 99-100%', 'Gini Coefficient', 'var(ln(Wealth))' ], 'Data': [], 'Model': [] } base_ineq = Inequality(base_ss['bssmat_splus1'], base_params.omega_SS, base_params.lambdas, base_params.S, base_params.J) base_values = [ 1 - base_ineq.top_share(0.75), base_ineq.top_share(0.75) - base_ineq.top_share(0.5), base_ineq.top_share(0.5) - base_ineq.top_share(0.3), base_ineq.top_share(0.3) - base_ineq.top_share(0.2), base_ineq.top_share(0.2) - base_ineq.top_share(0.1), base_ineq.top_share(0.1) - base_ineq.top_share(0.01), base_ineq.top_share(0.01), base_ineq.gini(), base_ineq.var_of_logs() ] table_dict['Model'].extend(base_values) # get moments from Survey of Consumer Finances data scf = wealth.get_wealth_data() table_dict['Data'] = wealth.compute_wealth_moments(scf, base_params.lambdas) # Make df with dict so can use pandas functions table_df = pd.DataFrame.from_dict(table_dict) table = save_return_table(table_df, table_format, path, precision=3) return table
def macro_table_SS(base_ss, reform_ss, var_list=['Yss', 'Css', 'Kss', 'Lss', 'rss', 'wss'], table_format=None, path=None): ''' Create a table of macro aggregates from the steady-state solutions. Args: base_ss (dictionary): SS output from baseline run reform_ss (dictionary): SS output from reform run var_list (list): names of variable to use in table table_format (string): format to return table in: 'csv', 'tex', 'excel', 'json', if None, a DataFrame is returned path (string): path to save table to Returns: table (various): table in DataFrame or string format or `None` if saved to disk ''' table_dict = { 'Variable': [], 'Baseline': [], 'Reform': [], '% Change (or pp diff)': [] } for i, v in enumerate(var_list): table_dict['Variable'].append(VAR_LABELS[v]) table_dict['Baseline'].append(base_ss[v]) table_dict['Reform'].append(reform_ss[v]) if v != 'D/Y': diff = ((reform_ss[v] - base_ss[v]) / base_ss[v]) * 100 else: diff = (reform_ss['Dss'] / reform_ss['Yss'] - base_ss['Dss'] / base_ss['Yss']) table_dict['% Change (or pp diff)'].append(diff) # Make df with dict so can use pandas functions table_df = pd.DataFrame.from_dict( table_dict, orient='columns').set_index('Variable') table = save_return_table(table_df, table_format, path, precision=3) return table
def param_table(p, table_format='tex', path=None): ''' This function creates a table of model parameters for publication. Args: p (OG-USA Specifications class): baseline parameters object) table_format (string): format to save/return table as path (string): path to save table to Returns: table (string or DataFrame): table of tax rates ''' table = {'Symbol': [], 'Description': [], 'Value': []} for k, v in PARAM_LABELS.items(): table['Symbol'].append(v[1]) table['Description'].append(v[0]) value = getattr(p, k) if hasattr(value, '__len__') & ~isinstance(value, str): if value.ndim > 1: report = 'See elsewhere' else: report = ('[' + '{0:1.3f}'.format(value[0]) + '...' + '{0:1.3f}'.format(value[-1]) + ']') else: if isinstance(value, int) or isinstance(value, np.int64): report = str(value) elif isinstance(value, str): report = value else: if value < 0.0001: report = "{:.2E}".format(value) else: report = '{0:1.3f}'.format(value) table['Value'].append(report) table_df = pd.DataFrame.from_dict(table) table_str = save_return_table(table_df, table_format, path, precision=3) return table_str
def test_save_return_table(df, output_type, precision): test_str = utils.save_return_table(df, output_type, None, precision) assert isinstance(test_str, str)
def tax_rate_table(base_TxFuncEst, base_params, reform_TxFuncEst=None, reform_params=None, rate_type='ETR', start_year=DEFAULT_START_YEAR, num_years=10, table_format='tex', path=None): ''' Table of average tax rates over several years. Args: base_TxFuncEst(dictionary): Baseline tax function parameter estimates base_params (OG-USA Specifications class): baseline parameters object reform_TxFuncEst (dictionary): Reform tax function parameter estimates reform_params (OG-USA Specifications class): reform parameters object rate_type (string): Tax rate to include in table start_year (integer): year to start table num_years (integer): number of years to include in table table_format (string): format to save/return table as path (string): path to save table to Returns: table_str (string or DataFrame): table of tax rates ''' assert isinstance(start_year, (int, np.integer)) assert isinstance(num_years, (int, np.integer)) # Make sure both runs cover same time period if reform_TxFuncEst is not None: assert (base_params.start_year == reform_params.start_year) start_index = start_year - base_params.start_year years = list(np.arange(start_year, start_year + num_years, 1)) if reform_TxFuncEst is None: if rate_type == 'ETR': rates = base_TxFuncEst['tfunc_avg_etr'] * 100 elif rate_type == 'MTRx': rates = base_TxFuncEst['tfunc_avg_mtrx'] * 100 elif rate_type == 'MTRy': rates = base_TxFuncEst['tfunc_avg_mtry'] * 100 elif rate_type == 'all': etr_rates = base_TxFuncEst['tfunc_avg_etr'] * 100 mtrx_rates = base_TxFuncEst['tfunc_avg_mtrx'] * 100 mtry_rates = base_TxFuncEst['tfunc_avg_mtry'] * 100 else: raise ValueError( 'Value {!r} is not a valid rate_type'.format(rate_type)) if rate_type == 'all': # In case num_years is greater than number of years # tax function estimates are for len_rates = len(etr_rates[start_index:start_index + num_years]) table = { 'Year': years[:len_rates], VAR_LABELS['ETR']: etr_rates[start_index:start_index + num_years], VAR_LABELS['MTRx']: mtrx_rates[start_index:start_index + num_years], VAR_LABELS['MTRy']: mtry_rates[start_index:start_index + num_years] } else: len_rates = len(rates[start_index:start_index + num_years]) table = { 'Year': years[:len_rates], VAR_LABELS[rate_type]: rates[start_index:start_index + num_years] } else: if rate_type == 'ETR': base_rates = base_TxFuncEst['tfunc_avg_etr'] * 100 reform_rates = reform_TxFuncEst['tfunc_avg_etr'] * 100 elif rate_type == 'MTRx': base_rates = base_TxFuncEst['tfunc_avg_mtrx'] * 100 reform_rates = reform_TxFuncEst['tfunc_avg_mtrx'] * 100 elif rate_type == 'MTRy': base_rates = base_TxFuncEst['tfunc_avg_mtrx'] * 100 reform_rates = reform_TxFuncEst['tfunc_avg_mtrx'] * 100 elif rate_type == 'all': base_etr_rates = base_TxFuncEst['tfunc_avg_etr'] * 100 base_mtrx_rates = base_TxFuncEst['tfunc_avg_mtrx'] * 100 base_mtry_rates = base_TxFuncEst['tfunc_avg_mtry'] * 100 reform_etr_rates = reform_TxFuncEst['tfunc_avg_etr'] * 100 reform_mtrx_rates = reform_TxFuncEst['tfunc_avg_mtrx'] * 100 reform_mtry_rates = reform_TxFuncEst['tfunc_avg_mtry'] * 100 else: raise ValueError( 'Value {!r} is not a valid rate_type'.format(rate_type)) if rate_type == 'all': len_rates = len(base_etr_rates[start_index:start_index + num_years]) table = { 'Year': years[:len_rates], 'Baseline ' + VAR_LABELS['ETR']: base_etr_rates[start_index:start_index + num_years], 'Reform ' + VAR_LABELS['ETR']: reform_etr_rates[start_index:start_index + num_years], 'Differences in ' + VAR_LABELS['ETR']: reform_etr_rates[start_index:start_index + num_years] - base_etr_rates[start_index:start_index + num_years], 'Baseline ' + VAR_LABELS['MTRx']: base_mtrx_rates[start_index:start_index + num_years], 'Reform ' + VAR_LABELS['MTRx']: reform_mtrx_rates[start_index:start_index + num_years], 'Differences in ' + VAR_LABELS['MTRx']: reform_mtrx_rates[start_index:start_index + num_years] - base_mtrx_rates[start_index:start_index + num_years], 'Baseline ' + VAR_LABELS['MTRy']: base_mtry_rates[start_index:start_index + num_years], 'Reform ' + VAR_LABELS['MTRy']: reform_mtry_rates[start_index:start_index + num_years], 'Differences in ' + VAR_LABELS['MTRy']: reform_mtry_rates[start_index:start_index + num_years] - base_mtry_rates[start_index:start_index + num_years] } else: len_rates = len(base_rates[start_index:start_index + num_years]) table = { 'Year': years[:len_rates], 'Baseline ' + VAR_LABELS[rate_type]: base_rates[start_index:start_index + num_years], 'Reform ' + VAR_LABELS[rate_type]: reform_rates[start_index:start_index + num_years], 'Difference': reform_rates[start_index:start_index + num_years] - base_rates[start_index:start_index + num_years] } table_df = (pd.DataFrame.from_dict(table, orient='columns')).transpose() table_df.columns = table_df.iloc[0].astype('int').astype('str') table_df.reindex(table_df.index.drop('Year')) table_df.drop('Year', inplace=True) table_str = save_return_table(table_df, table_format, path, precision=2) return table_str
def macro_table(base_tpi, base_params, reform_tpi=None, reform_params=None, var_list=['Y', 'C', 'K', 'L', 'r', 'w'], output_type='pct_diff', num_years=10, include_SS=True, include_overall=True, start_year=DEFAULT_START_YEAR, table_format=None, path=None): ''' Create a table of macro aggregates. Args: base_tpi (dictionary): TPI output from baseline run base_params (OG-USA Specifications class): baseline parameters object reform_tpi (dictionary): TPI output from reform run reform_params (OG-USA Specifications class): reform parameters object var_list (list): names of variable to use in table output_type (string): type of plot, can be: 'pct_diff': plots percentage difference between baselien and reform ((reform-base)/base) 'diff': plots difference between baseline and reform (reform-base) 'levels': variables in model units num_years (integer): number of years to include in table include_SS (bool): whether to include the steady-state results in the table include_overall (bool): whether to include results over the entire budget window as a column in the table start_year (integer): year to start table table_format (string): format to return table in: 'csv', 'tex', 'excel', 'json', if None, a DataFrame is returned path (string): path to save table to Returns: table (various): table in DataFrame or string format or `None` if saved to disk ''' assert isinstance(start_year, (int, np.integer)) assert isinstance(num_years, (int, np.integer)) # Make sure both runs cover same time period if reform_tpi is not None: assert (base_params.start_year == reform_params.start_year) year_vec = np.arange(start_year, start_year + num_years) start_index = start_year - base_params.start_year # Check that reform included if doing pct_diff or diff plot if output_type == 'pct_diff' or output_type == 'diff': assert (reform_tpi is not None) year_list = year_vec.tolist() if include_overall: year_list.append(str(year_vec[0]) + '-' + str(year_vec[-1])) if include_SS: year_list.append('SS') table_dict = {'Year': year_list} for i, v in enumerate(var_list): if output_type == 'pct_diff': # multiple by 100 so in percentage points results = (((reform_tpi[v] - base_tpi[v]) / base_tpi[v]) * 100) results_years = results[start_index:start_index + num_years] results_overall = ( (reform_tpi[v][start_index:start_index + num_years].sum() - base_tpi[v][start_index:start_index + num_years].sum()) / base_tpi[v][start_index:start_index + num_years].sum()) * 100 results_SS = results[-1] results_for_table = results_years if include_overall: results_for_table = np.append(results_for_table, results_overall) if include_SS: results_for_table = np.append(results_for_table, results_SS) table_dict[VAR_LABELS[v]] = results_for_table elif output_type == 'diff': results = reform_tpi[v] - base_tpi[v] results_years = results[start_index:start_index + num_years] results_overall = ( (reform_tpi[v][start_index:start_index + num_years].sum() - base_tpi[v][start_index:start_index + num_years].sum())) results_SS = results[-1] results_for_table = results_years if include_overall: results_for_table = np.append(results_for_table, results_overall) if include_SS: results_for_table = np.append(results_for_table, results_SS) table_dict[VAR_LABELS[v]] = results_for_table else: results_years = base_tpi[v][start_index:start_index + num_years] results_overall = results_years.sum() results_SS = base_tpi[v][-1] results_for_table = results_years if include_overall: results_for_table = np.append(results_for_table, results_overall) if include_SS: results_for_table = np.append(results_for_table, results_SS) table_dict[VAR_LABELS[v] + ' Baseline'] = results_for_table if reform_tpi is not None: results_years = reform_tpi[v][start_index:start_index + num_years] results_overall = results_years.sum() results_SS = reform_tpi[v][-1] results_for_table = results_years if include_overall: results_for_table = np.append(results_for_table, results_overall) if include_SS: results_for_table = np.append(results_for_table, results_SS) table_dict[VAR_LABELS[v] + ' Reform'] = results_for_table # Make df with dict so can use pandas functions table_df = pd.DataFrame.from_dict( table_dict, orient='columns').set_index('Year').transpose() table_df.reset_index(inplace=True) table_df.rename(columns={'index': 'Variable'}, inplace=True) table = save_return_table(table_df, table_format, path) return table
def dynamic_revenue_decomposition(base_params, base_tpi, base_ss, reform_params, reform_tpi, reform_ss, num_years=10, include_SS=True, include_overall=True, start_year=DEFAULT_START_YEAR, table_format=None, path=None): ''' This function decomposes the source of changes in tax revenues to determine the percentage change in individual and payroll tax receipt that can be attributed to macroeconomic feedback effects. Args: base_params (OG-USA Specifications class): baseline parameters object base_tpi (dictionary): TP output from baseline run base_ss (dictionary): SS output from baseline run reform_params (OG-USA Specifications class): reform parameters object reform_tpi (dictionary): TP output from reform run reform_ss (dictionary): SS output from reform run num_years (integer): number of years to include in table include_SS (bool): whether to include the steady-state results in the table include_overall (bool): whether to include results over the entire budget window as a column in the table start_year (integer): year to start table table_format (string): format to return table in: 'csv', 'tex', 'excel', 'json', if None, a DataFrame is returned path (string): path to save table to Returns: table (various): table in DataFrame or string format or `None` if saved to disk .. note:: The decomposition is the following: 1. Simulate the baseline and reform in OG-USA. Save the resulting series of tax revenues. Call these series for the baseline and reform A and D, respectively. 2. Create a third revenue series that is computed using the baseline behavior (i.e., `bmat_s` and `n_mat`) and macro variables (`tr`, `bq`, `r`, `w`), but with the tax function parameter estimates from the reform policy. Call this series B. 3. Create a fourth revenue series that is computed using the reform behavior (i.e., `bmat_s` and `n_mat`) and tax functions estimated on the reform tax policy, but the macro variables (`tr`, `bq`, `r`, `w`) from the baseline. Call this series C. 3. Calculate the percentage difference between B and A -- call this the "static" change from the macro model. Calculate the percentage difference between C and B -- call this the behavioral effects. Calculate the percentage difference between D and C -- call this the macroeconomic effect. One can apply the percentage difference from the macro feedback effect to the microsimulation model ("static") revenue estimate from the policy change to produce an estimate of the revenue including macro feedback. ''' assert isinstance(start_year, (int, np.integer)) assert isinstance(num_years, (int, np.integer)) # Make sure both runs cover same time period assert (base_params.start_year == reform_params.start_year) year_vec = np.arange(start_year, start_year + num_years) start_index = start_year - base_params.start_year year_list = year_vec.tolist() if include_overall: year_list.append(str(year_vec[0]) + '-' + str(year_vec[-1])) if include_SS: year_list.append('SS') table_dict = {'Year': year_list} T, S, J = base_params.T, base_params.S, base_params.J base_etr_params_4D = np.tile( base_params.etr_params.reshape(T, S, 1, base_params.etr_params.shape[2]), (1, 1, J, 1)) reform_etr_params_4D = np.tile( reform_params.etr_params.reshape(T, S, 1, reform_params.etr_params.shape[2]), (1, 1, J, 1)) series_A = tax.income_tax_liab(base_tpi['r_hh'][:T], base_tpi['w'][:T], base_tpi['bmat_s'], base_tpi['n_mat'][:T, :, :], base_ss['factor_ss'], 0, None, 'TPI', base_params.e, base_etr_params_4D, base_params) series_B = tax.income_tax_liab(base_tpi['r_hh'][:T], base_tpi['w'][:T], base_tpi['bmat_s'], base_tpi['n_mat'][:T, :, :], base_ss['factor_ss'], 0, None, 'TPI', base_params.e, reform_etr_params_4D, base_params) series_C = tax.income_tax_liab(base_tpi['r_hh'][:T], base_tpi['w'][:T], reform_tpi['bmat_s'], reform_tpi['n_mat'][:T, :, :], base_ss['factor_ss'], 0, None, 'TPI', reform_params.e, reform_etr_params_4D, reform_params) series_D = tax.income_tax_liab(reform_tpi['r_hh'][:T], reform_tpi['w'][:T], reform_tpi['bmat_s'], reform_tpi['n_mat'][:T, :, :], base_ss['factor_ss'], 0, None, 'TPI', reform_params.e, reform_etr_params_4D, reform_params) pop_weights = (np.squeeze(base_params.lambdas) * np.tile(np.reshape(base_params.omega[:T, :], (T, S, 1)), (1, 1, J))) base_tax_yr = (series_A * pop_weights).sum(1).sum(1) reform_tax_yr = (series_D * pop_weights).sum(1).sum(1) series_B_tax_yr = (series_B * pop_weights).sum(1).sum(1) series_C_tax_yr = (series_C * pop_weights).sum(1).sum(1) pct_diff_tax1 = (((series_B_tax_yr - base_tax_yr) / base_tax_yr) * 100) pct_diff_tax2 = (((series_C_tax_yr - series_B_tax_yr) / series_B_tax_yr) * 100) pct_diff_tax3 = (((reform_tax_yr - series_C_tax_yr) / series_C_tax_yr) * 100) pct_diff_tax1_overall = pct_diff_tax1[start_index:start_index + num_years].mean() pct_diff_tax2_overall = pct_diff_tax2[start_index:start_index + num_years].mean() pct_diff_tax3_overall = pct_diff_tax3[start_index:start_index + num_years].mean() pct_diff_tax1_SS = pct_diff_tax1[-1] pct_diff_tax2_SS = pct_diff_tax2[-1] pct_diff_tax3_SS = pct_diff_tax3[-1] if include_overall: tax1_for_table = np.append( pct_diff_tax1[start_index:start_index + num_years], pct_diff_tax1_overall) tax2_for_table = np.append( pct_diff_tax2[start_index:start_index + num_years], pct_diff_tax2_overall) tax3_for_table = np.append( pct_diff_tax3[start_index:start_index + num_years], pct_diff_tax3_overall) if include_SS: tax1_for_table = np.append(tax1_for_table, pct_diff_tax1_SS) tax2_for_table = np.append(tax2_for_table, pct_diff_tax2_SS) tax3_for_table = np.append(tax3_for_table, pct_diff_tax3_SS) table_dict = { 'Year': year_list, 'Pct Change due to tax rates': tax1_for_table, 'Pct Change due to behavior': tax2_for_table, 'Pct Change due to macro': tax3_for_table } # Make df with dict so can use pandas functions table_df = pd.DataFrame.from_dict( table_dict, orient='columns').set_index('Year').transpose() table_df.reset_index(inplace=True) table_df.rename(columns={'index': 'Variable'}, inplace=True) table = save_return_table(table_df, table_format, path) return table
def gini_table(base_ss, base_params, reform_ss=None, reform_params=None, var_list=['cssmat'], table_format=None, path=None): ''' Creates table with measures of the Gini coefficient: overall, across lifetime earnings group, and across age. Args: base_ss (dictionary): SS output from baseline run base_params (OG-USA Specifications class): baseline parameters object reform_ss (dictionary): SS output from reform run reform_params (OG-USA Specifications class): reform parameters object var_list (list): names of variable to use in table table_format (string): format to return table in: 'csv', 'tex', 'excel', 'json', if None, a DataFrame is returned path (string): path to save table to Returns: table (various): table in DataFrame or string format or `None` if saved to disk ''' table_dict = {'Steady-State Variable': [], 'Gini Type': [], 'Baseline': []} if reform_ss: table_dict['Reform'] = [] table_dict['% Change'] = [] for i, v in enumerate(var_list): base_ineq = Inequality(base_ss[v], base_params.omega_SS, base_params.lambdas, base_params.S, base_params.J) if reform_ss: reform_ineq = Inequality(reform_ss[v], reform_params.omega_SS, reform_params.lambdas, reform_params.S, reform_params.J) table_dict['Steady-State Variable'].extend([VAR_LABELS[v], '', '']) table_dict['Gini Type'].extend( ['Overall', 'Lifetime Income Group, $j$', 'Age , $s$']) base_values = np.array([ base_ineq.gini(), base_ineq.gini(type='ability'), base_ineq.gini(type='age') ]) table_dict['Baseline'].extend(list(base_values)) if reform_ss: reform_values = np.array([ reform_ineq.gini(), reform_ineq.gini(type='ability'), reform_ineq.gini(type='age') ]) table_dict['Reform'].extend(list(reform_values)) table_dict['% Change'].extend( list(((reform_values - base_values) / base_values) * 100)) # Make df with dict so can use pandas functions table_df = pd.DataFrame.from_dict(table_dict) table = save_return_table(table_df, table_format, path, precision=3) return table
def ineq_table(base_ss, base_params, reform_ss=None, reform_params=None, var_list=['cssmat'], table_format=None, path=None): ''' Creates table with various inequality measures in the model steady-state. Args: base_ss (dictionary): SS output from baseline run base_params (OG-USA Specifications class): baseline parameters object reform_ss (dictionary): SS output from reform run reform_params (OG-USA Specifications class): reform parameters object var_list (list): names of variable to use in table table_format (string): format to return table in: 'csv', 'tex', 'excel', 'json', if None, a DataFrame is returned path (string): path to save table to Returns: table (various): table in DataFrame or string format or `None` if saved to disk ''' table_dict = { 'Steady-State Variable': [], 'Inequality Measure': [], 'Baseline': [] } if reform_ss: table_dict['Reform'] = [] table_dict['% Change'] = [] for i, v in enumerate(var_list): base_ineq = Inequality(base_ss[v], base_params.omega_SS, base_params.lambdas, base_params.S, base_params.J) if reform_ss: reform_ineq = Inequality(reform_ss[v], reform_params.omega_SS, reform_params.lambdas, reform_params.S, reform_params.J) table_dict['Steady-State Variable'].extend( [VAR_LABELS[v], '', '', '', '']) table_dict['Inequality Measure'].extend([ 'Gini Coefficient', 'Var of Logs', '90/10 Ratio', 'Top 10% Share', 'Top 1% Share' ]) base_values = np.array([ base_ineq.gini(), base_ineq.var_of_logs(), base_ineq.ratio_pct1_pct2(0.90, 0.10), base_ineq.top_share(0.1), base_ineq.top_share(0.01) ]) table_dict['Baseline'].extend(list(base_values)) if reform_ss: reform_values = np.array([ reform_ineq.gini(), reform_ineq.var_of_logs(), reform_ineq.ratio_pct1_pct2(0.90, 0.10), reform_ineq.top_share(0.1), reform_ineq.top_share(0.01) ]) table_dict['Reform'].extend(list(reform_values)) table_dict['% Change'].extend( list(((reform_values - base_values) / base_values) * 100)) # Make df with dict so can use pandas functions table_df = pd.DataFrame.from_dict(table_dict) table = save_return_table(table_df, table_format, path, precision=3) return table