get_bartik_data

get_bartik_data(N=300, seed=1234)

Synthetic data for a Bartik (shift-share) IV application on immigration and wages.

DGP

Unobserved confounder: local_demand ~ N(0, 1)

First stage (immigration on bartik_instrument, conditional on log_population): immigration = 0.5 + 0.7bartik_instrument + 0.9local_demand + N(0, 0.5) → bartik_instrument is relevant; bartik ⊥ local_demand (exogenous)

Outcome (structural equation): wages = 8 + 0.5local_demand + TRUE_EFFECTimmigration + 0.2*log_population + N(0, 1) TRUE_EFFECT = -0.3

OVB for naive OLS (wages ~ immigration + log_population): Partial bias from local_demand ≈ 0.5 * 0.9/Var(immigration|log_pop) > 0 β_OLS on immigration ≈ -0.3 + positive_bias → attenuated (less negative or positive) β_IV on immigration ≈ -0.3 (recovers the true effect)

Parameters

Name Type Description Default
N int Number of observations (regions). Default is 300. 300
seed int Random seed. Default is 1234. 1234

Returns

Name Type Description
pandas.DataFrame Columns: wages, immigration, log_population, bartik_instrument.

Examples

import pyfixest as pf

data = pf.get_bartik_data()

# OLS is attenuated by unobserved local demand, IV recovers the true -0.3
pf.etable(
    [
        pf.feols("wages ~ immigration + log_population", data),
        pf.feols("wages ~ log_population | immigration ~ bartik_instrument", data),
    ]
)
wages
(1) (2)
coef
immigration 0.002
(0.053)
-0.384***
(0.097)
log_population 0.726***
(0.201)
1.158***
(0.235)
Intercept 6.713***
(0.399)
6.092***
(0.451)
stats
Observations 300 300
R2 0.046 -
Significance levels: * p < 0.05, ** p < 0.01, *** p < 0.001. Format of coefficient cell: Coefficient (Std. Error)