Skip to content

Commit

Permalink
remove time varying Discount Factor
Browse files Browse the repository at this point in the history
  • Loading branch information
alanlujan91 committed Mar 7, 2024
1 parent cf41b42 commit 523566e
Show file tree
Hide file tree
Showing 23 changed files with 135 additions and 157 deletions.
21 changes: 0 additions & 21 deletions code/estimark/agents.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,27 +23,6 @@


class TempConsumerType(AgentType):
def __init__(self, cycles=1, **kwds):
"""Make a new consumer type.
Parameters
----------
cycles : int
Number of times the sequence of periods should be solved.
time_flow : boolean
Whether time is currently "flowing" forward for this instance.
Returns
-------
None
"""
# Initialize a basic AgentType
super().__init__(cycles=cycles, **kwds)
# This estimation uses age-varying discount factors as
# estimated by Cagetti (2003), so switch from time_inv to time_vary
self.add_to_time_vary("DiscFac")
self.del_from_time_inv("DiscFac")

def check_restrictions(self):
return None
Expand Down
60 changes: 30 additions & 30 deletions code/estimark/estimation.py
Original file line number Diff line number Diff line change
Expand Up @@ -157,21 +157,21 @@ def get_initial_guess(agent_name):
res = pd.read_csv(csv_file_path, header=None)
initial_guess = res.iloc[:2, 1].astype(float).tolist()
except (FileNotFoundError, IndexError):
initial_guess = [options["init_DiscFacAdj"], options["init_CRRA"]]
initial_guess = [options["init_DiscFac"], options["init_CRRA"]]

return initial_guess


# Define the objective function for the simulated method of moments estimation
def simulate_moments(params, agent, agent_name):
"""A quick check to make sure that the parameter values are within bounds.
Far flung falues of DiscFacAdj or CRRA might cause an error during solution or
Far flung falues of DiscFac or CRRA might cause an error during solution or
simulation, so the objective function doesn't even bother with them.
"""
DiscFacAdj, CRRA = params
DiscFac, CRRA = params

# Update the agent with a new path of DiscFac based on this DiscFacAdj (and a new CRRA)
agent.DiscFac = [b * DiscFacAdj for b in options["timevary_DiscFac"]]
# Update the agent with a new path of DiscFac based on this DiscFac (and a new CRRA)
agent.DiscFac = DiscFac
agent.CRRA = CRRA

if "(Stock)" in agent_name and "Portfolio" in agent_name:
Expand Down Expand Up @@ -227,31 +227,31 @@ def simulate_moments(params, agent, agent_name):

def smm_obj_func(params, agent, moments, agent_name):
"""The objective function for the SMM estimation. Given values of discount factor
adjuster DiscFacAdj, coeffecient of relative risk aversion CRRA, a base consumer
adjuster DiscFac, coeffecient of relative risk aversion CRRA, a base consumer
agent type, empirical data, and calibrated parameters, this function calculates
the weighted distance between data and the simulated wealth-to-permanent
income ratio.
Steps:
a) solve for consumption functions for (DiscFacAdj, CRRA)
a) solve for consumption functions for (DiscFac, CRRA)
b) simulate wealth holdings for many consumers over time
c) sum distances between empirical data and simulated medians within
seven age groupings
Parameters
----------
DiscFacAdj : float
DiscFac : float
An adjustment factor to a given age-varying sequence of discount factors.
I.e. DiscFac[t] = DiscFacAdj*timevary_DiscFac[t].
I.e. DiscFac[t] = DiscFac*timevary_DiscFac[t].
CRRA : float
Coefficient of relative risk aversion.
agent : ConsumerType
The consumer type to be used in the estimation, with all necessary para-
meters defined except the discount factor and CRRA.
bounds_DiscFacAdj : (float,float)
Lower and upper bounds on DiscFacAdj; if outside these bounds, the function
bounds_DiscFac : (float,float)
Lower and upper bounds on DiscFac; if outside these bounds, the function
simply returns a "penalty value".
bounds_DiscFacAdj : (float,float)
bounds_DiscFac : (float,float)
Lower and upper bounds on CRRA; if outside these bounds, the function
simply returns a "penalty value".
empirical_data : np.array
Expand Down Expand Up @@ -297,7 +297,7 @@ def calculate_se_bootstrap(
Parameters
----------
initial_estimate : [float,float]
The estimated [DiscFacAdj,CRRA], for use as an initial guess for each
The estimated [DiscFac,CRRA], for use as an initial guess for each
re-estimation in the bootstrap procedure.
N : int
Number of times to resample data and re-estimate the model.
Expand All @@ -309,7 +309,7 @@ def calculate_se_bootstrap(
Returns
-------
standard_errors : [float,float]
Standard errors calculated by bootstrap: [DiscFacAdj_std_error, CRRA_std_error].
Standard errors calculated by bootstrap: [DiscFac_std_error, CRRA_std_error].
"""
t_0 = time()
Expand Down Expand Up @@ -358,10 +358,10 @@ def smm_obj_func_bootstrap(params):

# Calculate the standard errors for each parameter
estimate_array = (np.array(estimate_list)).T
DiscFacAdj_std_error = np.std(estimate_array[0])
DiscFac_std_error = np.std(estimate_array[0])
CRRA_std_error = np.std(estimate_array[1])

return [DiscFacAdj_std_error, CRRA_std_error]
return [DiscFac_std_error, CRRA_std_error]


# =================================================================
Expand All @@ -380,7 +380,7 @@ def do_estimate_model(agent_name, estimation_agent, target_moments, initial_gues
def smm_obj_func_redux(params):
"""A "reduced form" of the SMM objective function, compatible with the optimizer.
Identical to smmObjectiveFunction, but takes only a single input as a length-2
list representing [DiscFacAdj,CRRA].
list representing [DiscFac,CRRA].
"""
return smm_obj_func(
params,
Expand All @@ -395,10 +395,10 @@ def smm_obj_func_redux(params):
initial_guess,
algorithm="scipy_neldermead",
upper_bounds=np.array(
[options["bounds_DiscFacAdj"][1], options["bounds_CRRA"][1]],
[options["bounds_DiscFac"][1], options["bounds_CRRA"][1]],
),
lower_bounds=np.array(
[options["bounds_DiscFacAdj"][0], options["bounds_CRRA"][0]],
[options["bounds_DiscFac"][0], options["bounds_CRRA"][0]],
),
# multistart=True,
error_handling="continue",
Expand All @@ -412,15 +412,15 @@ def smm_obj_func_redux(params):
minutes, seconds = divmod(time_to_estimate, 60)
print(f"Time to estimate: {int(minutes)} min, {int(seconds)} sec.")
print(f"Estimated model: {agent_name}")
print(f"Estimated values: DiscFacAdj={model_estimate[0]}, CRRA={model_estimate[1]}")
print(f"Estimated values: DiscFac={model_estimate[0]}, CRRA={model_estimate[1]}")

# Create the simple estimate table
estimate_results_file = tables_dir + agent_name + "_estimate_results.csv"

with open(estimate_results_file, "w") as f:
writer = csv.writer(f)

writer.writerow(["DiscFacAdj", model_estimate[0]])
writer.writerow(["DiscFac", model_estimate[0]])
writer.writerow(["CRRA", model_estimate[1]])
writer.writerow(["time_to_estimate", time_to_estimate])

Expand Down Expand Up @@ -469,7 +469,7 @@ def do_compute_se_boostrap(
minutes, seconds = divmod(time_to_bootstrap, 60)
print(f"Time to bootstrap: {int(minutes)} min, {int(seconds)} sec.")

print(f"Standard errors: DiscFacAdj--> {std_errors[0]}, CRRA--> {std_errors[1]}")
print(f"Standard errors: DiscFac--> {std_errors[0]}, CRRA--> {std_errors[1]}")

# Create the simple bootstrap table
bootstrap_results_file = tables_dir + agent_name + "_bootstrap_results.csv"
Expand All @@ -478,8 +478,8 @@ def do_compute_se_boostrap(
writer = csv.writer(f)
writer.writerow(
[
"DiscFacAdj",
"DiscFacAdj_standard_error",
"DiscFac",
"DiscFac_standard_error",
"CRRA",
"CRRA_standard_error",
],
Expand Down Expand Up @@ -521,7 +521,7 @@ def simulate_moments_redux(params):
fig.set_tight_layout(True)

axs[0].bar(range(n_moments), sensitivity[0, :], tick_label=moment_labels)
axs[0].set_title("DiscFacAdj")
axs[0].set_title("DiscFac")
axs[0].set_ylabel("Sensitivity")
axs[0].set_xlabel("Median W/Y Ratio")

Expand All @@ -545,25 +545,25 @@ def do_make_contour_plot(agent_name, estimation_agent, model_estimate, target_mo
DiscFac_star, CRRA_star = model_estimate
grid_density = 20 # Number of parameter values in each dimension
level_count = 100 # Number of contour levels to plot
DiscFacAdj_list = np.linspace(
DiscFac_list = np.linspace(
max(DiscFac_star - 0.25, 0.5),
min(DiscFac_star + 0.25, 1.05),
grid_density,
)
CRRA_list = np.linspace(max(CRRA_star - 5, 2), min(CRRA_star + 5, 8), grid_density)
CRRA_mesh, DiscFacAdj_mesh = np.meshgrid(CRRA_list, DiscFacAdj_list)
CRRA_mesh, DiscFac_mesh = np.meshgrid(CRRA_list, DiscFac_list)
smm_obj_levels = np.empty([grid_density, grid_density])
for j in range(grid_density):
DiscFacAdj = DiscFacAdj_list[j]
DiscFac = DiscFac_list[j]
for k in range(grid_density):
CRRA = CRRA_list[k]
smm_obj_levels[j, k] = smm_obj_func(
np.array([DiscFacAdj, CRRA]),
np.array([DiscFac, CRRA]),
agent=estimation_agent,
moments=target_moments,
agent_name=agent_name,
)
smm_contour = plt.contourf(CRRA_mesh, DiscFacAdj_mesh, smm_obj_levels, level_count)
smm_contour = plt.contourf(CRRA_mesh, DiscFac_mesh, smm_obj_levels, level_count)
t_end_contour = time()
time_to_contour = t_end_contour - t_start_contour

Expand Down
23 changes: 11 additions & 12 deletions code/estimark/parameters.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@
# Initial guess of the coefficient of relative risk aversion during estimation (rho)
init_CRRA = 5.0
# Initial guess of the adjustment to the discount factor during estimation (beth)
init_DiscFacAdj = 0.99
init_DiscFac = 0.99
# Bounds for beth; if violated, objective function returns "penalty value"
bounds_DiscFacAdj = [0.5, 1.5]
bounds_DiscFac = [0.5, 1.5]
# Bounds for rho; if violated, objective function returns "penalty value"
bounds_CRRA = [1.1, 20.0]

Expand All @@ -64,12 +64,12 @@
SabelhausSong=ss_variances,
)

# Age-varying discount factors over the lifecycle, lifted from Cagetti (2003)
# Get the directory containing the current file and construct the full path to the CSV file
csv_file_path = Path(__file__).resolve().parent / ".." / "data" / "Cagetti2003.csv"
# timevary_DiscFac = np.genfromtxt(csv_file_path) * 0.0 + 1.0 # TODO
# constant_DiscFac = np.ones_like(timevary_DiscFac)
timevary_DiscFac = np.ones_like(inc_calib["PermShkStd"])
# # Age-varying discount factors over the lifecycle, lifted from Cagetti (2003)
# # Get the directory containing the current file and construct the full path to the CSV file
# csv_file_path = Path(__file__).resolve().parent / ".." / "data" / "Cagetti2003.csv"
# # timevary_DiscFac = np.genfromtxt(csv_file_path) * 0.0 + 1.0 # TODO
# # constant_DiscFac = np.ones_like(timevary_DiscFac)
# timevary_DiscFac = np.ones_like(inc_calib["PermShkStd"])

# Survival probabilities over the lifecycle
liv_prb = parse_ssa_life_table(
Expand Down Expand Up @@ -116,11 +116,10 @@
"num_agents": num_agents,
"bootstrap_size": bootstrap_size,
"seed": seed,
"init_DiscFacAdj": init_DiscFacAdj,
"init_DiscFac": init_DiscFac,
"init_CRRA": init_CRRA,
"bounds_DiscFacAdj": bounds_DiscFacAdj,
"bounds_DiscFac": bounds_DiscFac,
"bounds_CRRA": bounds_CRRA,
"timevary_DiscFac": timevary_DiscFac,
}

# -----------------------------------------------------------------------------
Expand All @@ -131,6 +130,7 @@
init_consumer_objects = {
**init_lifecycle,
"CRRA": init_CRRA,
"DiscFac": init_DiscFac,
"Rfree": Rfree,
"PermGroFac": inc_calib["PermGroFac"],
"PermGroFacAgg": 1.0,
Expand All @@ -151,7 +151,6 @@
"aXtraCount": aXtraCount,
"aXtraNestFac": exp_nest,
"LivPrb": liv_prb,
"DiscFac": timevary_DiscFac,
"AgentCount": num_agents,
"seed": seed,
"tax_rate": 0.0,
Expand Down
4 changes: 2 additions & 2 deletions content/tables/IndShockSub(Labor)Market_estimate_results.csv
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
DiscFacAdj,0.9610311710007147
DiscFac,0.9610311710007147
CRRA,20.0
time_to_estimate,169.89158630371094
time_to_estimate,174.0795018672943
params,"[0.9610311710007147, 20.0]"
criterion,114.86969241191717
start_criterion,114.86969241191717
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
DiscFacAdj,0.9672837526561269
DiscFac,0.9672837526561269
CRRA,20.0
time_to_estimate,175.07212805747986
time_to_estimate,180.29548740386963
params,"[0.9672837526561269, 20.0]"
criterion,115.43440076933648
start_criterion,115.43440076933648
Expand Down
18 changes: 9 additions & 9 deletions content/tables/IndShockSub(Stock)Market_estimate_results.csv
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
DiscFacAdj,0.9466358833023842
CRRA,3.4163818274425566
time_to_estimate,265.59967708587646
params,"[0.9466358833023842, 3.4163818274425566]"
criterion,263.57452934480165
start_criterion,263.5745293465149
start_params,"[0.9466358835993146, 3.4163818155178634]"
DiscFac,0.946635883013375
CRRA,3.4163818390123857
time_to_estimate,274.5633170604706
params,"[0.946635883013375, 3.4163818390123857]"
criterion,263.5745293428449
start_criterion,263.57452934480165
start_params,"[0.9466358833023842, 3.4163818274425566]"
algorithm,scipy_neldermead
direction,minimize
n_free,2
message,Optimization terminated successfully.
success,True
n_criterion_evaluations,137
n_criterion_evaluations,141
n_derivative_evaluations,
n_iterations,72
n_iterations,74
4 changes: 2 additions & 2 deletions content/tables/IndShock_estimate_results.csv
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
DiscFacAdj,0.9354653321855162
DiscFac,0.9354653321855162
CRRA,3.6415024998929013
time_to_estimate,253.86704754829407
time_to_estimate,263.70834851264954
params,"[0.9354653321855162, 3.6415024998929013]"
criterion,249.01488060992747
start_criterion,249.01488060992747
Expand Down
12 changes: 6 additions & 6 deletions content/tables/PortfolioSub(Labor)Market_estimate_results.csv
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
DiscFacAdj,1.0154424685349777
DiscFac,1.0154424685349777
CRRA,9.806412073325795
time_to_estimate,359.0212163925171
time_to_estimate,355.2289125919342
params,"[1.0154424685349777, 9.806412073325795]"
criterion,65.97027813743722
start_criterion,65.97027813749862
start_params,"[1.015442468418258, 9.806412081394452]"
start_criterion,65.97027813743722
start_params,"[1.0154424685349777, 9.806412073325795]"
algorithm,scipy_neldermead
direction,minimize
n_free,2
message,Optimization terminated successfully.
success,True
n_criterion_evaluations,137
n_criterion_evaluations,133
n_derivative_evaluations,
n_iterations,71
n_iterations,69
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
DiscFacAdj,1.021531027302729
CRRA,6.06596228373667
time_to_estimate,456.2026319503784
params,"[1.021531027302729, 6.06596228373667]"
criterion,92.71761323086302
start_criterion,92.71928624880582
start_params,"[1.021500632139196, 6.065893601845634]"
DiscFac,1.0215310271927214
CRRA,6.065962292352818
time_to_estimate,402.04997158050537
params,"[1.0215310271927214, 6.065962292352818]"
criterion,92.7176131910088
start_criterion,92.71761323086302
start_params,"[1.021531027302729, 6.06596228373667]"
algorithm,scipy_neldermead
direction,minimize
n_free,2
message,Optimization terminated successfully.
success,True
n_criterion_evaluations,191
n_criterion_evaluations,160
n_derivative_evaluations,
n_iterations,87
n_iterations,70
4 changes: 2 additions & 2 deletions content/tables/PortfolioSub(Stock)Market_estimate_results.csv
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
DiscFacAdj,0.5
DiscFac,0.5
CRRA,16.02486136184392
time_to_estimate,160.68801999092102
time_to_estimate,168.6807029247284
params,"[0.5, 16.02486136184392]"
criterion,276.8831690170802
start_criterion,276.8831690170802
Expand Down
Loading

0 comments on commit 523566e

Please sign in to comment.