Created
December 5, 2023 04:23
-
-
Save jamesbrandecon/aabda33fb775957f6c25b0ddc1230c82 to your computer and use it in GitHub Desktop.
A basic implementation of Bayesian (linear) instrumental variables regression with a single endogenous variable and a single IV. This is just a byproduct of me trying to learn more about Turing.jl and Bayesian estimation, but I'm hoping it's useful to someone as an example/starting point.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Plots | |
using StatsPlots, Turing | |
using Distributions, LinearAlgebra, Random, FillArrays | |
Random.seed!(12334455) | |
# ------------------------------------------------------- | |
# Models/functions for OLS and IV | |
# Only implemented with a single RHS variable -- easy | |
# to extend to multiple | |
# ------------------------------------------------------- | |
@model function bayesian_linreg(data) | |
N = length(data[:,1]) | |
X = data[:,2] | |
# Priors for alpha and beta | |
alpha ~ Normal(0, 0.2) | |
beta ~ Normal(0, 0.5) | |
# Prior for sigma | |
sigma ~ Exponential(1) | |
# Calculate mu | |
mu = alpha .+ X * beta | |
# Likelihood | |
for i in 1:N | |
data[i,1] ~ Normal(mu[i], sigma) | |
end | |
end | |
@model function bayesian_iv_onevar(data, IV, endog_cols) | |
Y = data[:,1] | |
endog = data[:,endog_cols] | |
N = length(Y) | |
# Priors for alphaY and alphaX | |
alphaY ~ Normal(0, 0.2) | |
alphaX ~ Normal(0, 0.2) | |
# Prior for beta | |
beta ~ Normal(0, 0.5) | |
# Prior for gamma | |
gamma ~ Normal(0, 0.5) | |
# Prior for correlation matrix Rho | |
Rho ~ LKJ(2, 1) | |
# Prior for scale parameters Sigma | |
Sigma ~ Exponential(1) | |
# Calculate muY and muX | |
muX = alphaX .+ gamma .* IV | |
muY = alphaY .+ beta .* muX | |
# Calculate covariance matrix | |
cov_matrix = LinearAlgebra.Diagonal(FillArrays.Fill(Sigma, 2)) .* Rho .* LinearAlgebra.Diagonal(FillArrays.Fill(Sigma, 2)); | |
# Likelihood for Y and X | |
# outcomes = hcat(Y, endog) | |
for i in 1:N | |
data[i,:] ~ MvNormal([muY[i], muX[i]], cov_matrix) | |
end | |
end | |
# Simulate a linear IV model | |
N = 2000 | |
error = randn(N) | |
IV = randn(N) | |
X = 1.3 .*IV + 0.7 .* error; | |
Y = X .* 0.5 + 0.5 .* error; | |
# Estimation | |
chain_ols = sample(bayesian_linreg([Y X]), Turing.NUTS(), 10_000); # linear regression | |
chain = sample(bayesian_iv_onevar([Y X], IV, 2), Turing.NUTS(), 10_000); # IV | |
# Plot chains | |
density(chain["beta"], label = "Posterior, IV") # pretty good! we beat endogeneity | |
density!(chain_ols["beta"], label = "Posterior, OLS") # bad -- endogeneity biases us | |
vline!([0.5], label = "True value") | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment