econirl

EconIRL is a Python package for structural dynamic discrete choice and inverse reinforcement learning. Use it to estimate forward-looking choice models, recover rewards, and predict behaviour under policy changes.

If you are new to these models, read this page as a map: first install the package, then choose an estimator, then use the estimator-specific pages for the math, assumptions, evidence, and examples.

Install

You can install EconIRL via:

pip install econirl

Estimators

Start with Choosing an Estimator for the estimator chooser, the canonical NFXP case, reward targets, transitions, and identification strategies.

The links below are method pages. Open one after you know the decision problem, the data you have, and the reward object you want to recover.

NFXP · CCP · MPEC · UFXP · NNES · TD-CCP · MCE-IRL · Neural MCE-IRL · AIRL · RHIP · f-IRL · GLADIUS · IQ-Learn

Theory

See Theory for the proof map behind the core estimators: soft Bellman equivalence, reward identification, classical DDC inversion, IRL identification boundaries, and the GLADIUS empirical-risk objective.

Replications

See Replications for the terse paper-number ledger. That page is about direct paper-number comparisons; broader synthetic evidence lives in the simulation studies.

Example

Here is an example that estimates Rust (1987):

from econirl.datasets import load_rust_bus, rust_bus_reward_spec
from econirl import NFXP

df = load_rust_bus()
reward = rust_bus_reward_spec(n_states=90)   # explicit features, your own names
model = NFXP(n_states=90, discount=0.9999, utility=reward)
model.fit(df, state="mileage_bin", action="replaced", id="bus_id")

print(model.summary())

The report shows data coverage, identification, estimates, uncertainty, and model fit.

================================================================================
                   Dynamic Discrete Choice Estimation Results
================================================================================
Method:      NFXP (Nested Fixed Point)    Observations:  9,410
Optimizer:   BHHH                         Individuals:   90
Family:      structural (linear utility)  Discount (β):  0.9999
                                          Scale (σ):     1.0
                                          Date:          2026-07-25

[1] DATA
  State space:          90 states x 2 actions
  Periods per individual: ~120
  Obs per state:        max 901 . p95 703 . p50 61 . p5 4 . min 2
  State coverage:       52/90 visited (58%)
  Single-action states: 14

[2] PRE-ESTIMATION CHECKS
  Reward features (K):  2
  Design rank:          2/2         Condition:          5.2e+01
  Contrast rank:        2/2       Contrast condition: 1.0e+02
  Verdict:              identified -- every reward parameter varies across actions

[3] FIRST-STAGE TRANSITION ESTIMATION
  Transition source: estimated from fitted panel
  Method:               empirical frequencies (multinomial MLE)
  Transitions used:     N = 9,410        Free parameters: 72
  Rows with full support: 90/180
  Std err across cells: max 0.2722 . p50 0.0258 . min 0.0000
  Held fixed in stage two (block-diagonal information).
--------------------------------------------------------------------------------
[4] RESULTS
  4a. Estimation
                         coef   std err       t   P>|t|   [0.025   0.975]
    operating_cost      0.0010    0.0004    2.58   0.010   0.0002   0.0018
    replacement_cost    3.0723    0.0740   41.54   0.000   2.9273   3.2172
  4b. Identification
    Hessian condition:  72,739.9     Min eigenvalue: 180.93
    Status:             Potentially weakly identified
  4c. Inference & fit
    Converged:   yes
    Iterations:  5
    Estimation time: 6.04 seconds
    Message:     Converged
    SE method:  robust (sandwich)
    Log-lik:    -1,900.33
    AIC/BIC:    3,804.7 / 3,819.0
    accuracy 94.9%
================================================================================

Counterfactuals

A fitted model evaluates policy changes. The counterfactual compares the baseline and counterfactual policies over long-run demand and welfare. Raising the replacement cost lowers the long-run replacement rate and lets buses run to higher mileage.

cf = model.counterfactual(replacement_cost=4.0)   # raise the replacement cost
print(cf.summary())
==========================================================================
                          Counterfactual Summary
==========================================================================
Type 3: reward parameter change      Oracle: none
Change:  parameters [0.001, 3.072] -> [0.001, 4.0]
--------------------------------------------------------------------------
                              baseline  counterfactual    change
  Action rate a=0 (long-run)     0.947           0.971    +0.023
  Action rate a=1 (long-run)     0.053           0.029    -0.023
  Long-run state mean           10.502          16.612    +6.110
  Expected value  E_mu[V]      339.703          -2.482  -342.186
--------------------------------------------------------------------------
  Policy shift |dpi|:   max 0.03 . p95 0.03 . p50 0.03 . p5 0.03
  Welfare change:       -342.29 utils (mean states) , -342.19 (stationary)
  (welfare = E[V], the inclusive value / consumer surplus)
==========================================================================