<jupyter_start><jupyter_text>respy showcase<jupyter_code>import io
import copy
import yaml
import numpy as np
import pandas as pd
import respy as rp
import seaborn as sns
import matplotlib.pyplot as plt
from IPython.display import Image
from pathlib import Path

from auxiliary.auxiliary import *<jupyter_output><empty_output><jupyter_text>Outline 1.  Package overview   2.  Introductory tutorial    2.1. Theoretical Framework    2.2. Specifying a model    2.3. Simulating data    2.4. Extending the model   3. Pre-implemented example models 4. Outlook     1. Package overview What is **respy**?- open source Python framework- simulation and estimation of some finite-horizon discrete choice dynamic programming models - class of models: Eckstein-Keane-Wolpin models (Aguirregabiria & Mira, 2009)  Class of models- Eckstein-Keane-Wolpin models- discrete choice dynamic life-cycle framework- reward function structure: experience accumulation and wages- economic applications: human capital investments, labor supply, occupational choice**Model components**- (any) number of choices and periods- initial conditions: lagged choices, initial experience, observable characteristics- unobserved heterogeneity: finite mixture models (types)- measurement error  Use cases**For research ...**- flexible model specification- build and solve structural models in weeks or months- extensive test suite**For learning & teaching ...**- extensive online documentation: tutorials, explanations, how-to guides- variety of pre-implemented example models that scale from toy examples to full empirical models- sandbox for theses & student projects- lecture materials: https://ekw-lectures.readthedocs.io  Steps of modeling 1. Theoretical development   2. Model implementation       2.1. Specification         2.2. Solution         2.3. Simulation     3. Calibration        3.1. Likelihood- or simulation-based criterion          3.2. Optimization $\rightarrow$ [estimagic](https://estimagic.readthedocs.io/en/latest/)   4. Validation and policy evaluation   Source code & documentation- developed on GitHub: https://github.com/OpenSourceEconomics/respy- online documentation: https://respy.readthedocs.io**Installation via conda**```bash$ conda config --add channels conda-forge$ conda install -c opensourceeconomics respy```  Source code on GitHub: https://github.com/OpenSourceEconomics/respy<jupyter_code>Image(filename='figures/respy-github.png')<jupyter_output><empty_output><jupyter_text>Testing<jupyter_code>Image(filename='figures/respy-ci.png')<jupyter_output><empty_output><jupyter_text>Online documentation: https://respy.readthedocs.io<jupyter_code>Image(filename='figures/respy-docs.png')<jupyter_output><empty_output><jupyter_text>Outline 1.  Package overview   2.  Introductory tutorial    2.1. Theoretical framework    2.2. Specifying a model    2.3. Simulating data    2.4. Extending the model   3. Pre-implemented example models 4. Outlook     2. Introductory tutorial Situational setup- <NAME> is stranded on a small island.- He goes fishing to make ends meet and will relax in his hammock when he is tired.- He cannot relax to often as he won't be able to eat otherwise.- The more he fishes, the better his fishing skills become.     2.1. Theoretical Framework: <NAME> on an island The economic problem- Robinson chooses every period $t = 0, \dots, T$ to either go fishing, $a = 0$, or spend the day in the hammock, $a = 1$.- If Robinson chooses to go fishing, he gains one additional unit of **experience** in the next period. Experience starts at zero.- The utility of a choice, $U(s_t, a_t)$, depends on the state $s_t$, which contains information on the individual's characteristics, and the chosen alternative $a_t$.- Robinson's utility for any given option can be denoted by$$\begin{align}    U(s_t, a_t) = \underbrace{W(s_t, a_t)}_{wage} + \underbrace{N(s_t, a_t)}_{non-pecuniary}\end{align}$$<jupyter_code>Image(filename="figures/tree_small.jpg")<jupyter_output><empty_output><jupyter_text>Working alternatives- For working alternatives like fishing, utility consists of two components, a *wage* and a *non-pecuniary* component.**Wage** $$\begin{align}        W(s_t, a_t)  &= r_{a} \exp\{x^w_{at} \beta^w_a + \epsilon_{at}\}\\    \ln(W(s_t, a_t)) &= \ln(r_a) + x^w_{at} \beta^w_a + \epsilon_{at}\end{align}$$- Components:    - $r_a$ is a market rental price for skill units.        - $x^w_{at}$ and $\beta^w_a$ are the choice- and time-dependent covariates and returns related to the wage signaled by superscript $w$.         - $\epsilon_{at}$ is a choice-specific random shock from the shock vector $\epsilon_t \sim \mathcal{N}(0, \Sigma)$ for all choices. **Non-pecuniary rewards** (for working alternatives)- Vector dot product of covariates $x_t^w$ and parameters $\beta^w$. - Superscript $w$ signals that the components belong to working alternatives.$$\begin{align}    N^w(s_t, a_t) = x_t^w\beta^w\end{align}$$  Non-working alternatives**Wage**$$\begin{align}W(s_t, a_t) = 0\end{align}$$**Non-pecuniary rewards**- Shocks enter the equation *additively*- Superscript $n$ stands for non-pecuniary$$    N^n(s_t, a_t) = x_t^n\beta^n + \epsilon_{at}$$ - Robinson's choice set thus consists of a "working" alternative which awards him a pecuniary compensation or wage and a "leisure" or non-working alternative which he derives a utility from, but no experience or wage. Experience in this basic model starts at zero and increases by one for every period $t$ in $1, ..., T$ where he chooses to go fishing.   Robinson's choice problem- Robinson is forward-looking and maximizes the expected present value of utility over the remaining lifetime  $\rightarrow$ select the optimal sequence of choices $\{a_t\}^T_{t = 0}$.- **Bellman equation**$$\begin{align}    V(s_{t})&= \max_{a_t} \, \{\underbrace{U(s_t, a_t)}_{\text{flow utility}}+ \delta \underbrace{\text{E}[ V(s_{t+1})]\}}_{\text{continuation value}}\end{align}$$- Realization of shocks becomes known in each period before Robinson makes his choice.- As shocks in period $t + 1$ are unknown to the individual in period $t$, utility must be maximized given the joint distribution of shocks in period $t + 1$ which is a maximization problem over a two-dimensional integral.- Denote the non-stochastic part of a state as $s^-$. Then, Robinson maximizes.$$\begin{equation}    V(s_t) = \max_{a_t}\{        U(s_t, a_t) + \delta \int_{\epsilon_{1, t + 1}} \int_{\epsilon_{0, t + 1}}        \max_{a_{t + 1}} V_{a_{t + 1}}(s^-_{t + 1}, \epsilon_{t + 1})        f_\epsilon(\epsilon_{t + 1})        d_{\epsilon_{0, t + 1}}, d_{\epsilon_{1, t + 1}}    \}\end{equation}$$   Outline 1.  Package overview   2.  Introductory tutorial    2.1. Theoretical framework    2.2. Specifying a model    2.3. Simulating data    2.4. Extending the model   3. Pre-implemented example models 4. Outlook     2.2. Specifying the model**respy** models consists of two main inputs:- `params`: (estimable) model parameters- `options` : model settings (number of periods, implementation details)   Model parameters: ``params``- Parameter vector of the model- Specified as a [MultiIndex pandas.DataFrame](https://pandas.pydata.org/pandas-docs/stable/user_guide/advanced.html) with two index levels.    1. *category*: which indicates certain parameters groups    2. *name*: which indicates a specific parameter    - read in parameters from a .csv-file:<jupyter_code>params = """category,name,value
delta,delta,0.95
wage_fishing,exp_fishing,0.1
nonpec_fishing,constant,-1
nonpec_hammock,constant,2.5
nonpec_hammock,not_fishing_last_period,-1
shocks_sdcorr,sd_fishing,1
shocks_sdcorr,sd_hammock,1
shocks_sdcorr,corr_hammock_fishing,-0.2
lagged_choice_1_hammock,constant,1
"""
params_basic = pd.read_csv(
    io.StringIO(params), sep=",", index_col=["category", "name"]
)

params_basic<jupyter_output><empty_output><jupyter_text>Model options: ``options``-  dictionary which contains additional information    - number of periods in the model    - size of the simulated sample    - implementation details like seeds    - covariates<jupyter_code>options_basic = {
    "n_periods": 10,
    "simulation_agents": 1000,
    "simulation_seed": 123,
    "covariates": {
        "constant": "1",
        "not_fishing_last_period": "lagged_choice_1 != 'fishing'",
    },
}
options_basic<jupyter_output><empty_output><jupyter_text>Outline 1.  Package overview   2.  Introductory tutorial    2.1. Theoretical framework    2.2. Specifying a model    2.3. Simulating data    2.4. Extending the model   3. Pre-implemented example models 4. Outlook     2.3. Simulating dataUsing the `params` and `options` we can set up a simulator using the function `get_simulate_func` and subsequently simulate a data for our selected parametrization.<jupyter_code>simulate = rp.get_simulate_func(params_basic, options_basic)
df_basic = simulate(params_basic)
df_basic.head(5)<jupyter_output><empty_output><jupyter_text>**Choice shares**<jupyter_code>plot_choice_shares(df_basic)<jupyter_output><empty_output><jupyter_text>**Transition matrix**<jupyter_code>data = pd.crosstab(df_basic.Lagged_Choice_1, df_basic.Choice, normalize=True)
sns.heatmap(data, cmap="Blues", annot=True);<jupyter_output><empty_output><jupyter_text>Outline 1.  Package overview   2.  Introductory tutorial    2.1. Theoretical framework    2.2. Specifying a model    2.3. Simulating data    2.4. Extending the model   3. Pre-implemented example models 4. Outlook     2.4. Extending the Model     2.4.1. Extension: Covariates**Covariates in the basic model**1. The constant, which is the simplest covariate2. The indicator whether Robinson went fishing last period.**New covariate:** *age*- assume Robinson's return to fishing decreases as he gets older.- assume that he arrives at the island with 16 years. - assume his age in each period, which we assume for now is one year, increases by one. I. Edit ``params``<jupyter_code>params_age = params_basic.copy()
params_age.loc[("wage_fishing", "age"), "value"] = -0.08
params_age<jupyter_output><empty_output><jupyter_text>II. Edit ``options``<jupyter_code>options_age = copy.deepcopy(options_basic)
options_age["covariates"].update({"age": "period + 16"})
options_age<jupyter_output><empty_output><jupyter_text>III. Simulate again<jupyter_code>simulate = rp.get_simulate_func(params_age, options_age)
df_age = simulate(params_age)<jupyter_output><empty_output><jupyter_text>$\rightarrow$ **Result:** Including the negative effect of age reduces the proportion of individuals that choose fishing, increasingly so in later periods.<jupyter_code>plot_choice_shares(df_age)<jupyter_output><empty_output><jupyter_text>2.4.2. Extension: Adding Choices- after some time on the island, Robinson meets Friday who can help him improve his fishing.- add the choice alternative `"friday"`    - affects the utility of fishing.     - choice should be available only once starting with the third period, and only after Robinson has been fishing before.  I. Edit `params` (loaded from .csv)- `wage_fishing` now includes a return to contemplation with Friday.- There is a new category,`nonpec_friday`, which captures the non-pecuniary reward for of spending a period with Friday.- The shock shock variance-covariance matrix has been altered to include the additional option.<jupyter_code>params_friday = pd.read_csv("params_files/robinson_crusoe_friday.csv", index_col=["category", "name"])
params_friday<jupyter_output><empty_output><jupyter_text>II. Adjust `options`**Covariates**- new covariate `"contemplation_with_friday"` is only affecting utility if ..    - Robinson is experienced in fishing    - only for one interaction with Friday<jupyter_code>options_friday = yaml.safe_load(open("option_files/options_friday.yml"))
options_friday["covariates"]<jupyter_output><empty_output><jupyter_text>**Negative choice set**- `"negative_choice_set"` can be used to restrict the choice Friday to the third and following periods<jupyter_code>options_friday["negative_choice_set"]<jupyter_output><empty_output><jupyter_text>III. Simulate<jupyter_code>simulate = rp.get_simulate_func(params_friday, options_friday)
df_friday = simulate(params_friday)
plot_choice_shares(df_friday, friday=True)<jupyter_output><empty_output><jupyter_text>2.4.3. Extension: Initial Experience- example of initial conditions: characteristics individuals enter the model with- assume in period $t=0$, Robinson will have $0$, $1$, or $2$ periods of experience in fishing.- this introduces a source of heterogeneity between agents I. Edit `params`- specify the distribution of initial experience via **probability mass functions**- keyword is `"initial_exp_fishing_*"` in the *category*-level of the index, where the asterisk needs to be replaced with the experience level. - the *name*-level, use `"probability"` to signal that the float in `"value"` is a probability. - specification: Robinson has equal probability to start out with 0, 1 or 2 periods of experience.<jupyter_code>params_initial_exp = params_basic.copy()
params_initial_exp.loc[ ("initial_exp_fishing_0", "probability"), "value"] = 0.33
params_initial_exp.loc[("initial_exp_fishing_1", "probability"), "value"] = 0.33
params_initial_exp.loc[ ("initial_exp_fishing_2", "probability"), "value"] = 0.34
params_initial_exp<jupyter_output><empty_output><jupyter_text>II. Adjust `options`$\rightarrow$ not necessary in this case! III. Simulate<jupyter_code>simulate = rp.get_simulate_func(params_initial_exp, options_basic)
df_exp = simulate(params_initial_exp)
plot_choice_prob_and_exp_level(df_basic)
plot_choice_prob_and_exp_level(df_exp)<jupyter_output><empty_output><jupyter_text>Comparing the plots shows that the share of engagement in fishing increases compared to the baseline scenario, as two thirds of Robinsons land on the island with previous experience in fishing.      2.4.4. Extension: Observables- add one observable characteristic to the baseline model, `"fishing_grounds"`- assume Robinson can end up, with a certain probability, on the side of the island which has `"poor"` or `"rich"` fishing grounds.- experiencing rich fishing grounds affects the **non-pecuniary reward** for fishing.  I. Add three additional rows to `params`- The probability with which Robinson will find himself in rich and in poor fishing grounds.- The return for being in a rich fishing ground, which here is set to be positive and constant.<jupyter_code>params_fish_ground = params_basic.copy()
params_fish_ground.loc[("observable_fishing_grounds_rich", "probability"), "value"] = 0.5
params_fish_ground.loc[("observable_fishing_grounds_poor", "probability"), "value"] = 0.5
params_fish_ground.loc[("nonpec_fishing", "rich_fishing_grounds"), "value"] = 0.5
params_fish_ground<jupyter_output><empty_output><jupyter_text>II. Adjust covariates in `options`<jupyter_code>options_fish_ground = options_basic.copy()
options_fish_ground["covariates"] = {
    "constant": "1",
    "not_fishing_last_period": "lagged_choice_1 != 'fishing'",
    "rich_fishing_grounds": "fishing_grounds == 'rich'",
}
options_fish_ground<jupyter_output><empty_output><jupyter_text>III. Simulate again<jupyter_code>simulate = rp.get_simulate_func(params_fish_ground, options_fish_ground)
df_fish_ground = simulate(params_fish_ground)<jupyter_output><empty_output><jupyter_text>As can be expected, Robinson engages in fishing more often if he is stranded on the side of the island with rich fishing grounds.<jupyter_code>plot_fishing_grounds(df_fish_ground)<jupyter_output><empty_output><jupyter_text>Outline 1.  Package overview   2.  Introductory tutorial    2.1. Theoretical framework    2.2. Specifying a model    2.3. Simulating data    2.4. Extending the model     3. Pre-implemented example models 4. Outlook     3. Pre-implemented example models```pythonparams, options, data = rp.get_example_model()```  Toy models- based on the story of Robinson Crusoe- used in the [tutorials](https://respy.readthedocs.io/en/latest/tutorials/index.html) in the documentation**Models**- `robinson_crusoe_basic`- `robinson_crusoe_extended`**Advantages**- simple model structure- computationally feasible due to the small number of available choices and low number of periods in the models    $\rightarrow$ useful of learning & teaching<jupyter_code>_, _, data = rp.get_example_model("robinson_crusoe_basic")
plot_choice_shares(data)
_, _, data = rp.get_example_model("robinson_crusoe_extended")
plot_choice_shares(data, friday=True)<jupyter_output><empty_output><jupyter_text>Keane and Wolpin (1994)**Source**- <NAME>., & <NAME>. (1994). The Solution and Estimation of Discrete Choice Dynamic Programming Models by Simulation and Interpolation: Monte Carlo Evidence. *The Review of Economics and Statistics*, 648-672.**Characteristics**- four mutually exclusive alternatives that individuals can choose in each period (work in sectors `a` or `b`, invest in education, or stay home)- time horizon of 40 periods**Models**- `kw_94_one`- `kw_94_two`- `kw_94_three`<jupyter_code>plot_choices_kw(example="1994")<jupyter_output><empty_output><jupyter_text>Keane and Wolpin (1997)**Source*** <NAME>., & <NAME>. (1997). The Career Decisions of Young Men. *Journal of Political Economy*, 105(3), 473-522.**Characteristics*** five mutually exclusive choice alternatives (occupations `white-collar`, `blue-collar`, `military`, school and staying home)* basic and extended model specification with unobserved heterogeneity, measurement error, and initial experience* time horizon of 50 periods* empirical model calibrated to a sample of white men in the National Longitudinal Survey of Youth (NLSY)**Models**- `kw_97_basic`- `kw_97_extended`<jupyter_code>plot_choices_kw(example="1997")<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.10498361396767997, 'fraction_numerical': 0.014464911289411233, 'mean_word_length': 5.499816378993757, 'pattern_counts': {'":': 10, '<': 115, '<?xml version=': 0, '>': 115, 'https://': 8, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '27', 'dir': 'jupyter-structured-clean-dedup', 'id': '493379', 'license': 'MIT', 'n_tokens_mistral': 5530, 'n_tokens_neox': 5232, 'n_words': 1730, 'path': 'respy-showcase-slides.ipynb', 'repo_name': 'amageh/respy-tut', 'size': '17738'}