Demo of CCC for PSL Meetup

This notebook provides a demonstration of the Cost-of-Capital-Calculator (CCC) for the PSL Meetup on April 29, 2019.

To run this notebook, you will need to follow the instructions to install CCC as described in the CCC README here. In particular, you need to:

  • Install the Anaconda distribution of Python

  • Install the CCC package by typing conda install -c conda-forge ccc in the command prompt.

Once you follow the above, you will be ready to work with this Jupyter Notebook.

First things first, import necessary packages

# import packages
import pandas as pd
import numpy as np
from bokeh.plotting import figure, show
from bokeh.io import output_notebook
# import CCC classes that we'll work with
from ccc.data import Assets
from ccc.parameters import Specification, DepreciationParams
from ccc.calculator import Calculator
# to print bokeh plots inline
output_notebook()
Loading BokehJS ...

Create an instance of the Assets class

This is the class that contains the data that underlie CCC. The basic object is a Pandas DataFrame where each row represents a combination of a specific type of asset, industry (approximately 6-digit NAICS) and tax treatment. The columns represent names and codes for the asset and industry classifications, the tax depreciation rules used for that asset, and the rate of economic depreciation (delta).

assets = Assets()
assets.df.head(n=5)
Unnamed: 0 tax_treat assets bea_asset_code bea_ind_code Industry minor_code_alt major_asset_group minor_asset_group major_industry asset_name delta
0 0 corporate 0.0 RD32 110C Farms 111 Intellectual Property Intellectual Property Agriculture, forestry, fishing, and hunting Aerospace products and parts manufacturing 0.22
1 1 corporate 0.0 RD32 113F Forestry, fishing, and related activities 113 Intellectual Property Intellectual Property Agriculture, forestry, fishing, and hunting Aerospace products and parts manufacturing 0.22
2 2 corporate 0.0 RD32 113F Forestry, fishing, and related activities 114 Intellectual Property Intellectual Property Agriculture, forestry, fishing, and hunting Aerospace products and parts manufacturing 0.22
3 3 corporate 0.0 RD32 2110 Oil and gas extraction 211110 Intellectual Property Intellectual Property Mining Aerospace products and parts manufacturing 0.22
4 4 corporate 0.0 RD32 2120 Mining, except oil and gas 212110 Intellectual Property Intellectual Property Mining Aerospace products and parts manufacturing 0.22

Create instances of the two parameters classes

The Specification class contains many of the model parameters, although depreciation system parameters are contained in the DepreciationParams class. Both are required arguments for the Calculator object.

A Specification object has methods that load the data from a file that contains the default parameter values (default_parameters.json) and then stores them as attributes of the Specification class object.

p.u looks into the instance of this class named p and executing the cell below will show you that p.u is dictionary containtin marginal tax rates on corporate and pass-through income.

Note that the Specification class has some arguments, such as call_tc, which defaults to False, but if set to True will call the Tax-Calculator to estimate marginal tax rates on individual filers’ income.

Similar to Specification, DepreciationParams loads default parameters from a JSON file, in this case the file tax_depreciation_rules.json.

# Create an instance of the Specification class
# p = Specification()
p = Specification(call_tc=True)
# Look at attributes
p.u
Calculator initial year =  2014
Calculator year =  2022
year:  2022
{'tau_pt': array([0.20291415]), 'tau_div': array([0.17179479]), 'tau_int': array([0.31126241]), 'tau_scg': array([0.2836037]), 'tau_lcg': array([0.18346882]), 'tau_td': array([0.20469421]), 'tau_h': array([0.03877468])}
{'c': array([0.21]), 'pt': array([0.20291415])}
# Create an instance of the DepreciationParams class
dp = DepreciationParams()
# Look at an attribute of the dp object
dp.asset[0]
OrderedDict([('value', {'life': 5.0, 'method': 'DB 200%'}),
             ('asset_name', 'Mainframes'),
             ('BEA_code', 'EP1A'),
             ('minor_asset_group', 'Computers and Software'),
             ('major_asset_group', 'Equipment'),
             ('ADS_life', 5.0),
             ('GDS_life', 5.0),
             ('system', 'GDS'),
             ('year', 2020)])

Create an instance of the Calculator class

This class does the calculations on the data. It takes as arguments the data object (named assets here) and the parameters object (named p here).

Excuting the cell below creates an instance of the calculator class with these data and parameters, but does not yet excecute any calculations.

# Create an instance of the Calculator class
calc1 = Calculator(p, dp, assets)

With an instance of the Calculator class created, we can start doing some calculations with these data.

For instance, we can compute a table of the share of corporate vs non-corporate assets across each industry.

# Look at shares of assets across industry
calc1.asset_share_table()
Industry Corporate Pass-Through
0 Agriculture, forestry, fishing, and hunting 0.309688 0.690312
1 Mining 0.826839 0.173161
2 Utilities 0.948540 0.051460
3 Construction 0.286840 0.713160
4 Manufacturing 0.859014 0.140986
5 Wholesale trade 0.715166 0.284834
6 Retail trade 0.728628 0.271372
7 Transportation and warehousing 0.789652 0.210348
8 Information 0.918722 0.081278
9 Finance and insurance 0.786056 0.213944
10 Real estate and rental and leasing 0.212052 0.787948
11 Professional, scientific, and technical services 0.501699 0.498301
12 Management of companies and enterprises 0.824397 0.175603
13 Administrative and waste management services 0.569110 0.430890
14 Educational services 0.590168 0.409832
15 Health care and social assistance 0.510425 0.489575
16 Arts, entertainment, and recreation 0.490811 0.509189
17 Accommodation and food services 0.482236 0.517764
18 Other services, except government 0.343467 0.656533

Specifying a reform policy

To see some more interesting results, we will want to create another Calculator object with a change in policy or economic assumptions. We can do this in a way analogous to our original instantiation of the Calculator object above. In particular, we’ll need to create a new Specification object (we can use the same underlying data, which was in the object we named assets).

In the code below, we’ll specify our “reform” as current law tax policy for 2026 (the baseline parameters above came from the default model year, 2019). In addition, we’ll increase the corporate income tax rate from 21 to 25%.

# Create another policy
p2 = Specification(year=2026)
p2.update_specification({'CIT_rate': 0.35})
calc2 = Calculator(p2, dp, assets)

Tabular output

Now with two Calculator objects named calc1 and calc2 (representing the baseline and reform policies), we are ready to compute some of the changes in effective tax rates, cost of capital, or other variables measured in this model.

We start with an overall summary table showing the marginal effective total tax rates (METTRs) for all investments, corporate investments, and pass-through investments under varying financing assumptions. This is done through the summary_table function. It takes a calculator object as an argument.

# Look at differences in METTRs between the two policies
calc1.summary_table(calc2) # calc1 is the baseline, calc2 the reform
Marginal Effective Total Tax Rate Under Baseline Policy Marginal Effective Total Tax Rate Under Reform Policy Change from Baseline (pp)
0 Overall 17.385422 25.403326 8.017904
1 Corporations 17.428895 28.035541 10.606646
2 Equity Financed 20.321015 34.294894 13.973878
3 Debt Financed 6.660793 -2.327833 -8.988626
4 Pass-Through Entities 18.812173 23.397810 4.585637
5 Equity Financed 17.178244 23.098247 5.920003
6 Debt Financed 25.163912 24.787343 -0.376569

the Calculator.summary_table() method defaults to showing the results for the METTR, but there is a keyword argument that would allow you to view the output for other variables computed in CCC. We can use this to see changes in the cost of capital (denoted by \(\rho\) in the model):

# Look at how the cost of capital changed
calc1.summary_table(calc2, output_variable='rho')
Cost of Capital Under Baseline Policy Cost of Capital Under Reform Policy Change from Baseline (pp)
0 Overall 5.656019 6.263947 0.607928
1 Corporations 5.658997 6.493061 0.834064
2 Equity Financed 6.571207 7.968742 1.397536
3 Debt Financed 3.723999 3.396877 -0.327121
4 Pass-Through Entities 5.652469 5.990843 0.338374
5 Equity Financed 6.321854 6.808519 0.486665
6 Debt Financed 4.016359 3.996250 -0.020109

One can also save results to disk by specifying an output type (‘excel’, ‘json’, ‘csv’, ‘tex’) and a file path:

# Save these results to disk
calc1.summary_table(calc2, output_variable='rho', output_type='excel', path='cc_table.xlsx')

There are also Calculator methods to compute summary tables by asset type or industry. These are computed in the next two cells.

# Summary by asset type
calc1.asset_summary_table(calc2)
Category Marginal Effective Total Tax Rate Under Baseline Policy Marginal Effective Total Tax Rate Under Reform Policy Change from Baseline (pp)
0 Overall 17.385422 25.403326 8.017904
1 Corporate 17.428895 28.035541 10.606646
2 Equipment 6.378304 22.198307 15.820003
3 Structures 18.079919 27.585133 9.505214
4 Intellectual Property 6.378304 10.914820 4.536516
5 Inventories 28.943514 39.720019 10.776504
6 Land 26.038860 35.629608 9.590748
7 Pass-through 18.812173 23.397810 4.585637
8 Equipment 1.948677 14.897821 12.949144
9 Structures 17.439967 21.502642 4.062675
10 Intellectual Property 1.948677 6.085711 4.137034
11 Inventories 25.029232 29.369039 4.339807
12 Land 21.844677 25.670063 3.825386
# Summary by industry
calc1.industry_summary_table(calc2)
Category Marginal Effective Total Tax Rate Under Baseline Policy Marginal Effective Total Tax Rate Under Reform Policy Change from Baseline (pp)
0 Overall 17.385422 25.403326 8.017904
1 Corporate 17.428895 28.035541 10.606646
2 Agriculture, forestry, fishing, and hunting 18.298771 30.621670 12.322899
3 Mining 9.355980 17.646210 8.290230
4 Utilities 7.403845 19.798819 12.394974
5 Construction 18.838676 30.349240 11.510564
6 Manufacturing 17.725594 26.830751 9.105157
7 Wholesale trade 23.188460 34.273842 11.085383
8 Retail trade 24.179499 34.690033 10.510534
9 Transportation and warehousing 10.639291 20.393471 9.754180
10 Information 10.034240 24.539591 14.505351
11 Finance and insurance 18.373608 30.264878 11.891270
12 Real estate and rental and leasing 24.087083 33.721519 9.634436
13 Professional, scientific, and technical ser... 14.266593 25.403173 11.136579
14 Management of companies and enterprises 22.177149 32.248505 10.071355
15 Administrative and waste management services 13.969707 26.515287 12.545580
16 Educational services 22.179268 31.613808 9.434540
17 Health care and social assistance 20.317482 30.832650 10.515168
18 Arts, entertainment, and recreation 15.213585 26.326474 11.112889
19 Accommodation and food services 23.766349 34.095181 10.328832
20 Other services, except government 20.522378 29.799384 9.277005
21 Pass-through 18.812173 23.397810 4.585637
22 Agriculture, forestry, fishing, and hunting 15.876157 22.523466 6.647308
23 Mining 5.274190 11.663757 6.389567
24 Utilities 3.285505 13.167828 9.882323
25 Construction 16.084501 22.106145 6.021644
26 Manufacturing 14.207660 19.167293 4.959633
27 Wholesale trade 21.047185 26.159069 5.111883
28 Retail trade 21.275141 26.050928 4.775787
29 Transportation and warehousing 6.820432 14.128465 7.308033
30 Information 5.985239 17.050742 11.065503
31 Finance and insurance 18.248503 23.618762 5.370259
32 Real estate and rental and leasing 20.871296 24.725673 3.854377
33 Professional, scientific, and technical ser... 9.972917 17.301080 7.328162
34 Management of companies and enterprises 17.913126 22.858351 4.945225
35 Administrative and waste management services 9.605741 18.203833 8.598093
36 Educational services 17.893937 22.297889 4.403953
37 Health care and social assistance 16.036972 21.670206 5.633234
38 Arts, entertainment, and recreation 10.649402 17.958885 7.309483
39 Accommodation and food services 19.724755 24.515138 4.790384
40 Other services, except government 15.985057 20.612279 4.627222

Visualizations

If one wants to visualize the effects of changes in tax policy, the Calculator class has a few methods for this.

We can use the grouped_bar method to show differential effects across assets (the default):

# Visualizing changes by asset
aplot = calc1.grouped_bar(calc2)
show(aplot)

or we can change from the default asset category split to a split by industry by changing the value of the group_by_asset keyword argument:

# Visualizing changes by industry
iplot = calc1.grouped_bar(calc2, group_by_asset=False)
show(iplot)

There’s also a plot that illustrates the range of the effects of taxes on investments across asset types, by showing the min, max, and mean values:

# Plot to show variation in METTRs across assets
rplot = calc1.range_plot(calc2, output_variable='metr')
show(rplot)

changing to show the effects on pass-through businesses and for a different output variable:

# Plot to show variation in METTRs across assets
rplot2 = calc1.range_plot(calc2, corporate=False, output_variable='mettr')
show(rplot2)

There’s a bubble plot too, though it doesn’t yet allow for many options (currently only plots METTRs for corporate entities):

bplot = calc1.asset_bubble(calc2)
show(bplot)
WARNING:bokeh.core.validation.check:W-1000 (MISSING_RENDERERS): Plot has no renderers: Figure(id='1684', ...)
WARNING:bokeh.core.validation.check:W-1000 (MISSING_RENDERERS): Plot has no renderers: Figure(id='1742', ...)

Summary

This notebook provides a brief example of how one would work with CCC. Please explore the source code to see additional flexiblity in the functions. And please leave any questions or suggestions in the CCC repo at https://github.com/PSLmodels/Cost-of-Capital-Calculator/issues.

bw = calc1.bubble_widget(calc2)
show(bw)
WARNING:bokeh.core.validation.check:W-1000 (MISSING_RENDERERS): Plot has no renderers: Figure(id='2236', ...)
WARNING:bokeh.core.validation.check:W-1000 (MISSING_RENDERERS): Plot has no renderers: Figure(id='2179', ...)