econirl.NFXP

class econirl.NFXP(n_states=90, n_actions=2, discount=0.9999, utility=None, se_method='robust', n_bootstrap=400, se_seed=None, verbose=False)[source]

Bases: object

Sklearn-style NFXP estimator for dynamic discrete choice models.

The Nested Fixed Point (NFXP) algorithm estimates utility parameters by nesting the solution of the Bellman equation within likelihood maximization. This is the classic approach from Rust (1987, 1988).

Parameters:
  • n_states (int, default=90) – Number of discrete states (e.g., mileage bins).

  • n_actions (int, default=2) – Number of discrete actions (e.g., keep/replace).

  • discount (float, default=0.9999) – Time discount factor (beta).

  • utility (RewardSpec) – Utility specification as a RewardSpec. For the classic Rust bus model, use rust_bus_reward_spec(n_states) from econirl.datasets.

  • se_method (str, default="robust") – Method for computing standard errors. Options: “asymptotic”, “robust”, “clustered”, “bootstrap”, and “full_likelihood_bhhh”.

  • n_bootstrap (int, default=400) – Number of pairs-cluster bootstrap replications when se_method="bootstrap".

  • se_seed (int, optional) – Random seed for bootstrap standard errors.

  • verbose (bool, default=False) – Whether to print progress messages during estimation.

Variables:
  • params (dict) – Estimated parameters after fitting. Keys are parameter names (e.g., “operating_cost”, “replacement_cost”) and values are point estimates.

  • se (dict) – Standard errors for each parameter.

  • coef (numpy.ndarray) – Coefficients as a numpy array (sklearn convention).

  • log_likelihood (float) – Maximized log-likelihood value.

  • pvalues (dict) – P-values for each parameter (from Wald t-test).

  • policy (numpy.ndarray) – Estimated choice probabilities P(a|s) of shape (n_states, n_actions).

  • value (numpy.ndarray) – Estimated value function V(s) of shape (n_states,).

  • value_function (numpy.ndarray) – Alias for value_ (backward compatibility).

  • transitions (numpy.ndarray) – Original transition input. This is a two-dimensional keep matrix when transitions are estimated by the wrapper, or the supplied array.

  • transition_tensor (numpy.ndarray) – Canonical action-specific transition tensor with shape (n_actions, n_states, n_states).

  • transition_source (str) – Whether transitions were estimated from the fitted panel or supplied.

  • converged (bool) – Whether the optimization converged.

  • reward_spec (RewardSpec) – The reward specification used for estimation.

Examples

>>> from econirl.estimators import NFXP
>>> import pandas as pd
>>>
>>> df = pd.DataFrame({
...     "bus_id": [0, 0, 1, 1],
...     "mileage": [10, 20, 15, 30],
...     "replaced": [0, 0, 0, 1],
... })
>>>
>>> model = NFXP(n_states=90)
>>> model.fit(df, state="mileage", action="replaced", id="bus_id")
>>> print(model.params_)
__init__(n_states=90, n_actions=2, discount=0.9999, utility=None, se_method='robust', n_bootstrap=400, se_seed=None, verbose=False)[source]

Initialize the NFXP estimator.

Parameters:
  • n_states (int, default=90) – Number of discrete states.

  • n_actions (int, default=2) – Number of discrete actions.

  • discount (float, default=0.9999) – Time discount factor (beta).

  • utility (RewardSpec) – Utility specification as a RewardSpec. For the classic Rust bus model, use rust_bus_reward_spec(n_states) from econirl.datasets.

  • se_method (str, default="robust") – Method for computing standard errors.

  • n_bootstrap (int, default=400) – Number of pairs-cluster bootstrap replications when se_method="bootstrap".

  • se_seed (int, optional) – Random seed for bootstrap standard errors.

  • verbose (bool, default=False) – Whether to print progress messages.

fit(data, state=None, action=None, id=None, transitions=None, reward=None)[source]

Fit the NFXP estimator to data.

Parameters:
  • data (pandas.DataFrame or Panel or TrajectoryPanel) – Panel data with observations. When a DataFrame is passed, state, action, and id column names are required. When a Panel/TrajectoryPanel is passed, column names are ignored.

  • state (str, optional) – Column name for the state variable (required for DataFrame input).

  • action (str, optional) – Column name for the action variable (required for DataFrame input).

  • id (str, optional) – Column name for the individual identifier (required for DataFrame input).

  • transitions (numpy.ndarray, optional) – Pre-estimated transition probabilities. Two forms are accepted. A 2D array of shape (n_states, n_states) is the keep-kernel for action 0; the replace action is built by resetting to state 0 (the Rust reset-on-replace default). A 3D array of shape (n_actions, n_states, n_states) is a full per-action transition tensor and is used as given, for action-dependent transitions. If None, transitions are estimated from the data.

  • reward (RewardSpec, optional) – Reward/utility specification. If provided, overrides the utility parameter passed at construction time.

Returns:

self – Returns self for method chaining.

Return type:

NFXP

property reward_matrix_: ndarray | None

Structural reward matrix R(s,a) of shape (n_states, n_actions).

Computes the utility matrix from the fitted parameters and the feature specification. Returns None if the model has not been fitted.

summary(alpha=0.05)[source]

Generate a formatted summary of estimation results.

Returns:

Human-readable summary of the estimation.

Return type:

str

Parameters:

alpha (float)

conf_int(alpha=0.05)[source]

Compute confidence intervals for parameters.

Parameters:

alpha (float, default=0.05) – Significance level. Returns (1 - alpha) confidence intervals.

Returns:

{param_name: (lower, upper)} confidence intervals.

Return type:

dict

Raises:

RuntimeError – If the model has not been fitted yet.

predict_proba(states)[source]

Predict choice probabilities for given states.

Parameters:

states (numpy.ndarray) – Array of state indices.

Returns:

Choice probabilities of shape (len(states), n_actions). Each row sums to 1.

Return type:

numpy.ndarray

simulate(n_agents, n_periods, seed=None, init_states=None)[source]

Simulate choices under the estimated policy.

Generates synthetic data by simulating agents making decisions according to the fitted model. Each agent starts from init_states (state 0 for everyone by default) and evolves according to the estimated transition probabilities and choice probabilities.

Parameters:
  • n_agents (int) – Number of agents to simulate.

  • n_periods (int) – Number of time periods per agent.

  • seed (int, optional) – Random seed for reproducibility.

  • init_states (numpy.ndarray, optional) – Initial states. None starts every agent at state 0. A length n_states vector is treated as a start distribution and sampled. A length n_agents array sets each agent’s start state directly.

Returns:

DataFrame with columns: - agent_id: Identifier for each agent (0 to n_agents-1) - period: Time period (0 to n_periods-1) - state: State at the beginning of the period - action: Action taken (sampled from estimated policy)

Return type:

pandas.DataFrame

Raises:

RuntimeError – If the model has not been fitted yet.

Examples

>>> model = NFXP(n_states=90)
>>> model.fit(data, state="mileage", action="replaced", id="bus_id")
>>> sim_data = model.simulate(n_agents=100, n_periods=50, seed=42)
>>> print(sim_data.head())
counterfactual(transitions=None, **param_changes)[source]

Compute outcomes under different parameter values.

Performs counterfactual analysis by solving the dynamic programming problem under alternative parameter values. This enables “what if” questions such as “what would the policy be if replacement cost were 15 instead of 10?”

Parameters:
  • transitions (numpy.ndarray, optional) – Alternative transition matrix or action-specific transition tensor. When supplied, reward parameters remain fixed.

  • **param_changes (float) – Keyword arguments specifying parameter changes. Keys must be valid parameter names, such as operating_cost or replacement_cost for rust_bus_reward_spec. Values are the counterfactual parameter values.

Returns:

Object containing: - params: Dictionary of all parameter values used - value_function: V(s) under new parameters - policy: P(a|s) under new parameters

Return type:

CounterfactualResult

Raises:
  • RuntimeError – If the model has not been fitted yet.

  • ValueError – If an unknown parameter name is provided.

Examples

>>> from econirl.datasets import rust_bus_reward_spec
>>> model = NFXP(n_states=90, utility=rust_bus_reward_spec(90))
>>> model.fit(data, state="mileage", action="replaced", id="bus_id")
>>>
>>> # What if replacement cost was higher?
>>> cf = model.counterfactual(replacement_cost=15.0)
>>> print(f"Original replacement cost: "
...       f"{model.params_['replacement_cost']:.2f}")
>>> print(f"Counterfactual replacement cost: "
...       f"{cf.params['replacement_cost']:.2f}")
>>> print(f"P(replace|state=50) changes from "
...       f"{model.predict_proba(np.array([50]))[0,1]:.3f} to "
...       f"{cf.policy[50,1]:.3f}")
>>>
>>> # Multiple parameter changes
>>> cf2 = model.counterfactual(
...     replacement_cost=15.0,
...     operating_cost=0.05,
... )