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 on your machine, 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
(orpip install cost-of-captial-calculator
) 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#
# To install ccc package (if not already):
import sys
if 'ccc' not in sys.modules:
!pip install cost-of-capital-calculator
Requirement already satisfied: cost-of-capital-calculator in /usr/share/miniconda3/envs/ccc-dev/lib/python3.12/site-packages (1.5.2)
Requirement already satisfied: taxcalc in /usr/share/miniconda3/envs/ccc-dev/lib/python3.12/site-packages (from cost-of-capital-calculator) (4.3.0)
Requirement already satisfied: pandas in /usr/share/miniconda3/envs/ccc-dev/lib/python3.12/site-packages (from cost-of-capital-calculator) (2.2.3)
Requirement already satisfied: bokeh in /usr/share/miniconda3/envs/ccc-dev/lib/python3.12/site-packages (from cost-of-capital-calculator) (3.6.0)
Requirement already satisfied: numpy in /usr/share/miniconda3/envs/ccc-dev/lib/python3.12/site-packages (from cost-of-capital-calculator) (2.0.2)
Requirement already satisfied: paramtools in /usr/share/miniconda3/envs/ccc-dev/lib/python3.12/site-packages (from cost-of-capital-calculator) (0.18.3)
Requirement already satisfied: Jinja2>=2.9 in /usr/share/miniconda3/envs/ccc-dev/lib/python3.12/site-packages (from bokeh->cost-of-capital-calculator) (3.1.4)
Requirement already satisfied: contourpy>=1.2 in /usr/share/miniconda3/envs/ccc-dev/lib/python3.12/site-packages (from bokeh->cost-of-capital-calculator) (1.3.0)
Requirement already satisfied: packaging>=16.8 in /usr/share/miniconda3/envs/ccc-dev/lib/python3.12/site-packages (from bokeh->cost-of-capital-calculator) (24.1)
Requirement already satisfied: pillow>=7.1.0 in /usr/share/miniconda3/envs/ccc-dev/lib/python3.12/site-packages (from bokeh->cost-of-capital-calculator) (11.0.0)
Requirement already satisfied: PyYAML>=3.10 in /usr/share/miniconda3/envs/ccc-dev/lib/python3.12/site-packages (from bokeh->cost-of-capital-calculator) (6.0.2)
Requirement already satisfied: tornado>=6.2 in /usr/share/miniconda3/envs/ccc-dev/lib/python3.12/site-packages (from bokeh->cost-of-capital-calculator) (6.4.1)
Requirement already satisfied: xyzservices>=2021.09.1 in /usr/share/miniconda3/envs/ccc-dev/lib/python3.12/site-packages (from bokeh->cost-of-capital-calculator) (2024.9.0)
Requirement already satisfied: python-dateutil>=2.8.2 in /usr/share/miniconda3/envs/ccc-dev/lib/python3.12/site-packages (from pandas->cost-of-capital-calculator) (2.9.0)
Requirement already satisfied: pytz>=2020.1 in /usr/share/miniconda3/envs/ccc-dev/lib/python3.12/site-packages (from pandas->cost-of-capital-calculator) (2024.1)
Requirement already satisfied: tzdata>=2022.7 in /usr/share/miniconda3/envs/ccc-dev/lib/python3.12/site-packages (from pandas->cost-of-capital-calculator) (2024.2)
Requirement already satisfied: marshmallow>=3.0.0 in /usr/share/miniconda3/envs/ccc-dev/lib/python3.12/site-packages (from paramtools->cost-of-capital-calculator) (3.23.0)
Requirement already satisfied: fsspec in /usr/share/miniconda3/envs/ccc-dev/lib/python3.12/site-packages (from paramtools->cost-of-capital-calculator) (2024.10.0)
Requirement already satisfied: sortedcontainers in /usr/share/miniconda3/envs/ccc-dev/lib/python3.12/site-packages (from paramtools->cost-of-capital-calculator) (2.4.0)
Requirement already satisfied: setuptools in /usr/share/miniconda3/envs/ccc-dev/lib/python3.12/site-packages (from taxcalc->cost-of-capital-calculator) (75.1.0)
Requirement already satisfied: numba in /usr/share/miniconda3/envs/ccc-dev/lib/python3.12/site-packages (from taxcalc->cost-of-capital-calculator) (0.60.0)
Requirement already satisfied: requests in /usr/share/miniconda3/envs/ccc-dev/lib/python3.12/site-packages (from taxcalc->cost-of-capital-calculator) (2.32.3)
Requirement already satisfied: MarkupSafe>=2.0 in /usr/share/miniconda3/envs/ccc-dev/lib/python3.12/site-packages (from Jinja2>=2.9->bokeh->cost-of-capital-calculator) (3.0.2)
Requirement already satisfied: six>=1.5 in /usr/share/miniconda3/envs/ccc-dev/lib/python3.12/site-packages (from python-dateutil>=2.8.2->pandas->cost-of-capital-calculator) (1.16.0)
Requirement already satisfied: llvmlite<0.44,>=0.43.0dev0 in /usr/share/miniconda3/envs/ccc-dev/lib/python3.12/site-packages (from numba->taxcalc->cost-of-capital-calculator) (0.43.0)
Requirement already satisfied: charset-normalizer<4,>=2 in /usr/share/miniconda3/envs/ccc-dev/lib/python3.12/site-packages (from requests->taxcalc->cost-of-capital-calculator) (3.4.0)
Requirement already satisfied: idna<4,>=2.5 in /usr/share/miniconda3/envs/ccc-dev/lib/python3.12/site-packages (from requests->taxcalc->cost-of-capital-calculator) (3.10)
Requirement already satisfied: urllib3<3,>=1.21.1 in /usr/share/miniconda3/envs/ccc-dev/lib/python3.12/site-packages (from requests->taxcalc->cost-of-capital-calculator) (2.2.3)
Requirement already satisfied: certifi>=2017.4.17 in /usr/share/miniconda3/envs/ccc-dev/lib/python3.12/site-packages (from requests->taxcalc->cost-of-capital-calculator) (2024.8.30)
# 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()
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
Using CPS
Calculator initial year = 2014
Calculator year = 2024
year: 2024
{'tau_pt': array([0.20106125]), 'tau_div': array([0.17460723]), 'tau_int': array([0.31307742]), 'tau_scg': array([0.28522881]), 'tau_lcg': array([0.18438707]), 'tau_td': array([0.20617498]), 'tau_h': array([0.03500351])}
{'c': array([0.21]), 'pt': array([0.20106125])}
# 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 | 18.616006 | 34.225300 | 15.609294 |
1 | Corporations | 19.289505 | 42.290467 | 23.000962 |
2 | Equity Financed | 22.125690 | 46.019810 | 23.894120 |
3 | Debt Financed | 9.097707 | 26.809930 | 17.712222 |
4 | Pass-Through Entities | 19.322439 | 22.541129 | 3.218690 |
5 | Equity Financed | 17.595430 | 22.463002 | 4.867572 |
6 | Debt Financed | 25.815628 | 22.992590 | -2.823038 |
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.776999 | 7.147965 | 1.370966 |
1 | Corporations | 5.825206 | 8.146925 | 2.321719 |
2 | Equity Financed | 6.721989 | 9.697451 | 2.975462 |
3 | Debt Financed | 3.925764 | 4.875811 | 0.950047 |
4 | Pass-Through Entities | 5.719536 | 5.957203 | 0.237667 |
5 | Equity Financed | 6.352442 | 6.751232 | 0.398790 |
6 | Debt Financed | 4.172939 | 4.019962 | -0.152977 |
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 | 18.616006 | 34.225300 | 15.609294 |
1 | Corporate | 19.289505 | 42.290467 | 23.000962 |
2 | Equipment | 12.268229 | 51.221033 | 38.952804 |
3 | Structures | 19.431798 | 37.100910 | 17.669112 |
4 | Intellectual Property | 9.379343 | 52.586216 | 43.206872 |
5 | Inventories | 28.801265 | 39.347759 | 10.546494 |
6 | Land | 26.056203 | 35.232088 | 9.175885 |
7 | Pass-through | 19.322439 | 22.541129 | 3.218690 |
8 | Equipment | 7.956112 | 14.162423 | 6.206311 |
9 | Structures | 17.855920 | 20.663326 | 2.807406 |
10 | Intellectual Property | 4.617759 | 6.134524 | 1.516765 |
11 | Inventories | 24.751484 | 28.432579 | 3.681095 |
12 | Land | 21.763692 | 24.776615 | 3.012923 |
# 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 | 18.616006 | 34.225300 | 15.609294 |
1 | Corporate | 19.289505 | 42.290467 | 23.000962 |
2 | Agriculture, forestry, fishing, and hunting | 20.534007 | 39.825732 | 19.291725 |
3 | Mining | 12.218682 | 40.334320 | 28.115637 |
4 | Utilities | 12.013905 | 35.617148 | 23.603243 |
5 | Construction | 20.687990 | 44.152309 | 23.464319 |
6 | Manufacturing | 18.982117 | 44.975519 | 25.993401 |
7 | Wholesale trade | 24.081817 | 44.175500 | 20.093683 |
8 | Retail trade | 24.739682 | 41.380739 | 16.641058 |
9 | Transportation and warehousing | 13.656180 | 39.123581 | 25.467401 |
10 | Information | 15.067469 | 45.626469 | 30.559000 |
11 | Finance and insurance | 20.429404 | 48.923692 | 28.494288 |
12 | Real estate and rental and leasing | 24.424992 | 37.288774 | 12.863782 |
13 | Professional, scientific, and technical ser... | 16.881945 | 52.644707 | 35.762762 |
14 | Management of companies and enterprises | 22.944220 | 45.750555 | 22.806335 |
15 | Administrative and waste management services | 17.130350 | 48.198261 | 31.067911 |
16 | Educational services | 22.747754 | 40.858592 | 18.110838 |
17 | Health care and social assistance | 21.572517 | 42.545889 | 20.973372 |
18 | Arts, entertainment, and recreation | 17.692689 | 40.552553 | 22.859863 |
19 | Accommodation and food services | 24.357493 | 40.406246 | 16.048752 |
20 | Other services, except government | 21.338903 | 39.922950 | 18.584046 |
21 | Pass-through | 19.322439 | 22.541129 | 3.218690 |
22 | Agriculture, forestry, fishing, and hunting | 17.532884 | 21.668586 | 4.135701 |
23 | Mining | 8.121768 | 10.993231 | 2.871463 |
24 | Utilities | 7.844139 | 12.469384 | 4.625245 |
25 | Construction | 17.465832 | 21.256867 | 3.791035 |
26 | Manufacturing | 15.324819 | 18.360023 | 3.035204 |
27 | Wholesale trade | 21.480848 | 25.256637 | 3.775790 |
28 | Retail trade | 21.562322 | 25.150418 | 3.588096 |
29 | Transportation and warehousing | 9.833258 | 13.410283 | 3.577025 |
30 | Information | 11.109830 | 17.293690 | 6.183859 |
31 | Finance and insurance | 19.118451 | 22.748909 | 3.630458 |
32 | Real estate and rental and leasing | 20.886514 | 23.843631 | 2.957117 |
33 | Professional, scientific, and technical ser... | 12.574331 | 16.524174 | 3.949843 |
34 | Management of companies and enterprises | 18.635533 | 21.998423 | 3.362890 |
35 | Administrative and waste management services | 12.789779 | 17.412865 | 4.623086 |
36 | Educational services | 18.401046 | 21.447133 | 3.046087 |
37 | Health care and social assistance | 17.245331 | 20.827518 | 3.582187 |
38 | Arts, entertainment, and recreation | 13.208242 | 17.230613 | 4.022371 |
39 | Accommodation and food services | 20.200659 | 23.633904 | 3.433245 |
40 | Other services, except government | 16.791841 | 19.785431 | 2.993590 |
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 type
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:
show(rplot)
# Plot to show variation in METTRs across assets
output_notebook()
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='p1409', ...)
WARNING:bokeh.core.validation.check:W-1000 (MISSING_RENDERERS): Plot has no renderers: figure(id='p1470', ...)
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 PSLmodels/Cost-of-Capital-Calculator#issues.