analyze_panel_iv_regression

source

analyze_panel_iv_regression(
    df,
    dv,
    endog,
    instruments,
    exog=None,
    *,
    entity=None,
    time=None,
    twoway=True,
    cluster_entity=True,
    format='gt',
)

Fit a panel IV (2SLS) regression absorbing entity (and time) fixed effects.

The panel analogue of :func:analyze_iv_regression and of Stata’s xtivreg2 ... fe: it instruments the endogenous regressor(s) while absorbing entity fixed effects (and, when twoway, time fixed effects), clustering by entity by default. The panel ids follow the usual expdpy resolution — explicit entity / time win, otherwise the pair declared by :func:expdpy.set_panel is used.

Parameters

Name Type Description Default
df pd.DataFrame Data frame containing the data. required
dv str Dependent (outcome) variable name. required
endog Sequence[str] | str Endogenous regressor name(s) to be instrumented. required
instruments Sequence[str] | str Excluded instrument name(s) (order condition: at least as many as endog). required
exog Sequence[str] | None Included exogenous regressor (control) names, if any. None
entity str | None Panel identifiers (unit and period). Resolved from :func:expdpy.set_panel when not passed; entity is required, time is needed only for the two-way specification. None
time str | None Panel identifiers (unit and period). Resolved from :func:expdpy.set_panel when not passed; entity is required, time is needed only for the two-way specification. None
twoway bool If True (default) absorb both entity and time fixed effects; if False absorb only entity fixed effects (one-way). True
cluster_entity bool If True (default) cluster the standard errors by entity. True
format Literal['gt', 'tex', 'md', 'df', 'html'] Output format for the rendered etable (see :func:analyze_iv_regression). 'gt'

Returns

Name Type Description
IVRegressionResult As :func:analyze_iv_regression, with the entity/time fixed effects absorbed.

Examples

Instrument night-time lights (a proxy for local economic activity) with lagged rainfall and drought across African regions, absorbing region and year fixed effects and clustering by region — a panel xtivreg2 fe. The first-stage F is well above 10:

import expdpy as ex
from expdpy.data import load_regional_conflict, load_regional_conflict_data_def

df = ex.set_labels(
    load_regional_conflict(), load_regional_conflict_data_def(), set_panel=True
)

result = ex.analyze_panel_iv_regression(
    df,
    dv="conflict",
    endog="log_lights_lag1",
    instruments=["rain_lag2", "drought_lag2"],
)
result.etable
result.first_stage_f
print(result.interpret())
This IV (2SLS) regression instruments **log_lights_lag1** with *rain_lag2, drought_lag2*, relating it to **conflict**. Two-stage least squares isolates the part of the endogenous regressor that moves with the instruments, purging the endogeneity that biases ordinary least squares.

- **log_lights_lag1** (instrumented): a one-unit increase is associated with conflict that is 0.296 lower (statistically significant at the 1% level).

The first-stage F is 25.3 — **above** the conventional weak-instrument threshold of 10, so the instruments are reasonably strong.
IV is trustworthy only when the instruments are both **relevant** (a strong first stage) and **excludable** — related to conflict solely through the instrumented regressor.

_These are associations, not causal effects. A causal reading needs a research design — see `explain('correlation_vs_causation')`._