{ "cells": [ { "cell_type": "markdown", "id": "fd4ff68a", "metadata": {}, "source": [ "# Estimating a quarterly RBC from annual data\n", "\n", "Many of the time series a macroeconomist would like to feed a DSGE model, such as quarterly national accounts or monthly labor-market data, are unavailable for much of the developing world. For many economies the only reliable long-running macroeconomic series are the annual national accounts compiled by the World Bank and national statistical offices.\n", "\n", "This poses a difficulty, because DSGE models are usually specified at a quarterly or higher frequency: the discount factor, the persistence of shocks, and the propagation of the business cycle are all calibrated to quarterly dynamics. Collapsing the model to an annual frequency to match the data would discard much of that structure.\n", "\n", "Mixed-frequency estimation offers an alternative. The model is kept at its quarterly frequency, the quarterly states are treated as latent, and they are linked to the available annual observations through the measurement equation. A year's observed GDP is the sum of its four unobserved quarters; a year-end stock is the value in the final quarter. The Kalman filter accommodates a series that is observed once every four periods and missing in between, and infers the quarterly path most consistent with both the data and the model's dynamics.\n", "\n", "This notebook works through that procedure on a single case study: Senegal, using annual World Bank data, with a simple quarterly RBC as the data-generating model." ] }, { "cell_type": "markdown", "id": "09ad67f7", "metadata": {}, "source": [ "
gEconpy. Install them into the same environment before running the cells below:\n",
"\n",
"pip install time_series_transformers\n",
"pip install git+https://github.com/jessegrabowski/pandas-datareader.git@main\n",
"\n",
"time_series_transformers provides the sklearn-style, invertible log and detrend transformers we use to preprocess the data. pandas-datareader pulls the Senegalese national-accounts series straight from the World Bank’s World Development Indicators API (we install from a fork because the upstream package does not yet run under pandas 3).\n",
"| \n", " | Y | \n", "C | \n", "I | \n", "
|---|---|---|---|
| Time | \n", "\n", " | \n", " | \n", " |
| 2020-01-01 | \n", "13374044739200 | \n", "9317054028600 | \n", "5.373646e+12 | \n", "
| 2021-01-01 | \n", "14249242374000 | \n", "9630093933000 | \n", "5.991010e+12 | \n", "
| 2022-01-01 | \n", "14797899753200 | \n", "10000187002300 | \n", "7.010006e+12 | \n", "
| 2023-01-01 | \n", "15427910099900 | \n", "10500062199900 | \n", "7.215624e+12 | \n", "
| 2024-01-01 | \n", "16362926523300 | \n", "10811669266800 | \n", "7.590262e+12 | \n", "
| \n", " | Y | \n", "C | \n", "I | \n", "
|---|---|---|---|
| Time | \n", "\n", " | \n", " | \n", " |
| 2020-01-01 | \n", "-0.033306 | \n", "-0.019595 | \n", "0.014944 | \n", "
| 2021-01-01 | \n", "-0.016471 | \n", "-0.024871 | \n", "0.110304 | \n", "
| 2022-01-01 | \n", "0.007551 | \n", "-0.010507 | \n", "0.107608 | \n", "
| 2023-01-01 | \n", "-0.016181 | \n", "0.004544 | \n", "0.024588 | \n", "
| 2024-01-01 | \n", "0.003663 | \n", "-0.004697 | \n", "-0.086461 | \n", "
\\[u_{t} = - \\frac{C_{t}^{1 - \\sigma_{C}}}{\\sigma_{C} - 1} - \\frac{L_{t}^{\\sigma_{L} + 1}}{\\sigma_{L} + 1}\\]
\n", "\\[\\operatorname{Set}\\left(\\left[ C_{t}, \\ L_{t}, \\ I_{t}, \\ K_{t}\\right]\\right)\\]
\n", "\\[U_{t} = \\beta U_{t+1} + u_{t}\\]
\n", "\\[C_{t} + I_{t} = K_{t-1} r_{t} + L_{t} w_{t}\\]
\n", "\\[K_{t} = I_{t} - K_{t-1} \\left(\\delta - 1\\right)\\]
\n", "\\[\\beta = 0.99\\]
\n", "\\[\\delta = 0.02\\]
\n", "\\[\\sigma_{C} = 1.5\\]
\n", "\\[\\sigma_{L} = 2.0\\]
\n", "\\[\\operatorname{Set}\\left(\\left[ K_{t-1}, \\ L_{t}\\right]\\right)\\]
\n", "\\[TC_{t} = - K_{t-1} r_{t} - L_{t} w_{t}\\]
\n", "\\[Y_{t} = A_{t} K_{t-1}^{\\alpha} L_{t}^{1 - \\alpha}\\]
\n", "\\[mc_{t} = 1\\]
\n", "\\[\\alpha = 0.35\\]
\n", "\\[\\log{\\left(A_{t} \\right)} = \\rho_{A} \\log{\\left(A_{t-1} \\right)} + \\epsilon_{A t}\\]
\n", "\\[\\operatorname{Set}\\left(\\left[ \\epsilon_{A t}\\right]\\right)\\]
\n", "\\[\\rho_{A} = 0.95\\]
\n", "Model Requirements \n", " \n", " Variable Shape Constraints Dimensions \n", " ──────────────────────────────────────────────────── \n", " alpha () None \n", " beta () None \n", " delta () None \n", " rho_A () None \n", " sigma_C () None \n", " sigma_L () None \n", " sigma_epsilon_A () Positive None \n", " error_sigma_Y () Positive None \n", " error_sigma_C () Positive None \n", " error_sigma_I () Positive None \n", " \n", " These parameters should be assigned priors inside a \n", " PyMC model block before calling the \n", " build_statespace_graph method. \n", "\n" ], "text/plain": [ "\u001b[3m Model Requirements \u001b[0m\n", " \n", " \u001b[1m \u001b[0m\u001b[1mVariable \u001b[0m\u001b[1m \u001b[0m \u001b[1m \u001b[0m\u001b[1mShape\u001b[0m\u001b[1m \u001b[0m \u001b[1m \u001b[0m\u001b[1mConstraints\u001b[0m\u001b[1m \u001b[0m \u001b[1m \u001b[0m\u001b[1mDimensions\u001b[0m\u001b[1m \u001b[0m \n", " ──────────────────────────────────────────────────── \n", " alpha \u001b[1m(\u001b[0m\u001b[1m)\u001b[0m \u001b[3;35mNone\u001b[0m \n", " beta \u001b[1m(\u001b[0m\u001b[1m)\u001b[0m \u001b[3;35mNone\u001b[0m \n", " delta \u001b[1m(\u001b[0m\u001b[1m)\u001b[0m \u001b[3;35mNone\u001b[0m \n", " rho_A \u001b[1m(\u001b[0m\u001b[1m)\u001b[0m \u001b[3;35mNone\u001b[0m \n", " sigma_C \u001b[1m(\u001b[0m\u001b[1m)\u001b[0m \u001b[3;35mNone\u001b[0m \n", " sigma_L \u001b[1m(\u001b[0m\u001b[1m)\u001b[0m \u001b[3;35mNone\u001b[0m \n", " sigma_epsilon_A \u001b[1m(\u001b[0m\u001b[1m)\u001b[0m Positive \u001b[3;35mNone\u001b[0m \n", " error_sigma_Y \u001b[1m(\u001b[0m\u001b[1m)\u001b[0m Positive \u001b[3;35mNone\u001b[0m \n", " error_sigma_C \u001b[1m(\u001b[0m\u001b[1m)\u001b[0m Positive \u001b[3;35mNone\u001b[0m \n", " error_sigma_I \u001b[1m(\u001b[0m\u001b[1m)\u001b[0m Positive \u001b[3;35mNone\u001b[0m \n", " \n", "\u001b[2;3m These parameters should be assigned priors inside a \u001b[0m\n", "\u001b[2;3m PyMC model block before calling the \u001b[0m\n", "\u001b[2;3m build_statespace_graph method. \u001b[0m\n" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "ss_mod.configure(\n", " observed_states=[\"Y\", \"C\", \"I\"],\n", " measurement_error=[\"Y\", \"C\", \"I\"],\n", " temporal_aggregation={\"Y\": \"mean\", \"C\": \"mean\", \"I\": \"mean\"},\n", " aggregation_period=4,\n", " mode=\"NUMBA\",\n", " solver=\"gensys\",\n", " use_adjoint_gradients=True,\n", " max_iter=20,\n", ")" ] }, { "cell_type": "code", "execution_count": 11, "id": "ff095f77", "metadata": {}, "outputs": [], "source": [ "# Variable groups for plotting\n", "deep_parameters = list(ss_mod.param_dict.keys())\n", "shock_sigmas = [f\"sigma_{name}\" for name in ss_mod.shock_names]\n", "noise_sigmas = [f\"error_sigma_{name}\" for name in ss_mod.error_states]" ] }, { "cell_type": "markdown", "id": "b308b369", "metadata": {}, "source": [ "## Shaping the data\n", "\n", "The Kalman filter runs on the quarterly grid, so we expand the annual series onto a quarterly index, leaving the three unobserved quarters of each year as `NaN`. `ge.prepare_mixed_frequency_data` does this; `observation_position=\"last\"` places each annual value in the fourth quarter, where the four-quarter cumulator window completes. The filter treats every `NaN`, including the empty quarters, the Hamilton-filter warmup, and the missing early investment figures, as a missing observation and skips the update step." ] }, { "cell_type": "code", "execution_count": 12, "id": "03f62a19", "metadata": {}, "outputs": [ { "data": { "text/html": [ "
| \n", " | Y | \n", "C | \n", "I | \n", "
|---|---|---|---|
| 2023-01-01 | \n", "NaN | \n", "NaN | \n", "NaN | \n", "
| 2023-04-01 | \n", "NaN | \n", "NaN | \n", "NaN | \n", "
| 2023-07-01 | \n", "NaN | \n", "NaN | \n", "NaN | \n", "
| 2023-10-01 | \n", "-0.016181 | \n", "0.004544 | \n", "0.024588 | \n", "
| 2024-01-01 | \n", "NaN | \n", "NaN | \n", "NaN | \n", "
| 2024-04-01 | \n", "NaN | \n", "NaN | \n", "NaN | \n", "
| 2024-07-01 | \n", "NaN | \n", "NaN | \n", "NaN | \n", "
| 2024-10-01 | \n", "0.003663 | \n", "-0.004697 | \n", "-0.086461 | \n", "