using LinearAlgebra, Distributions, Random
using Optim, ForwardDiff
using Tables, MarkdownTables
using StatsPlots
Monte Carlo Simulation with Julia (Growth Model)
Statistics
Structural equation modeling
Simulation
Julia
Learning note of using Julia for simulation
In this note, I’m trying to use the Julia language to run some simulations.
First, here’s an example of simulating multivariate normal random variables
Random.seed!(1234)
= [0, 1, 2]
μ = cov(randn(100, 3))
Σ = 200
n = rand(MvNormal(μ, Σ), n) y
3×200 Matrix{Float64}:
0.0540757 -0.102689 0.658599 0.611513 … 0.879624 0.605667 0.595295
1.14527 -0.222159 2.24221 1.30428 0.254144 2.05194 2.90419
2.6294 0.572331 1.47629 2.98324 4.10777 1.05924 1.56324
Growth Model Example
Specify implied moments from a growth model
growth_moments(Λ, α, Ψ, Θ) = (μ = Λ * α, Σ = Hermitian(Λ * Ψ * Λ') + Θ)
= [1 0
Λ 1 1
1 2
1 3]
= [0, 1]
α = Symmetric([1 0.2
Ψ 0.2 0.25])
= Symmetric([ 1 0.2 0.04 0.008
Θ 0.2 1 0.2 0.04
0.04 0.2 1 0.2
0.008 0.04 0.2 1]) # autoregressive structure
= growth_moments(Λ, α, Ψ, Θ) gm
(μ = [0, 1, 2, 3], Σ = [2.0 1.4 1.44 1.608; 1.4 2.65 2.3000000000000003 2.59; 1.44 2.3000000000000003 3.8 3.7; 1.608 2.59 3.7 5.45])
Simulate data from a growth model
= rand(MvNormal(growth_moments(Λ, α, Ψ, Θ)...), 500) sim_dat
4×500 Matrix{Float64}:
0.629762 -0.205364 1.64222 0.486685 … -0.292158 0.13341 -0.624102
1.95646 3.54633 -0.797253 0.608302 1.88673 1.03129 -0.378568
1.91765 2.56468 0.553998 3.44475 2.42096 3.01259 0.746786
1.88494 2.93066 0.570765 1.94388 0.564698 3.71769 0.984581
Fit a growth model using maximum likelihood estimation using Optim.jl
"""
growth_ll(α, Ψ, Θ, Λ, y)
Compute log-likelihood of the input parameters given data y
α = latent means
Ψ = latent variance and covariances
Θ = error covariances
Λ = loading matrix
"""
function growth_ll(α, Ψ, Θ, Λ, y)
= growth_moments(Λ, α, Ψ, Θ)
μhat, Σhat if !isposdef(Σhat)
return Inf
end
= MvNormal(μhat, Σhat)
d loglikelihood(MvNormal(μhat, Σhat), y)
end
growth_ll(α, Ψ, Θ, Λ, sim_dat)
"""
growth_ll(θ, Λ, y)
Compute log-likelihood of the input parameter vector given data y
"""
function growth_ll(θ, Λ, y)
= view(θ, 1:2)
α = reshape(θ[[3, 4, 4, 5]], (2, 2))
Ψ = [θ[6] * θ[7]^abs(i - j) for i in 1:4, j in 1:4]
Θ growth_ll(α, Ψ, Θ, Λ, y)
end
# Maximum likelihood estimation
# Starting values:
= vcat(α, Ψ[[1, 2, 4]], 1, .2)
θ₀ = optimize(x -> -growth_ll(x, Λ, sim_dat), θ₀, Newton(); autodiff=:forward) opt
* Status: success
* Candidate solution
Final objective value: 3.378396e+03
* Found with
Algorithm: Newton's Method
* Convergence measures
|x - x'| = 1.09e-07 ≰ 0.0e+00
|x - x'|/|x'| = 1.11e-07 ≰ 0.0e+00
|f(x) - f(x')| = 1.36e-12 ≰ 0.0e+00
|f(x) - f(x')|/|f(x')| = 4.04e-16 ≰ 0.0e+00
|g(x)| = 4.75e-12 ≤ 1.0e-08
* Work counters
Seconds run: 0 (vs limit Inf)
Iterations: 4
f(x) calls: 12
∇f(x) calls: 12
∇²f(x) calls: 4
Wrap into a function
function sim_θhat(n)
= rand(MvNormal(growth_moments(Λ, α, Ψ, Θ)...), n)
ysim = optimize(x -> -growth_ll(x, Λ, ysim), θ₀, Newton(); autodiff=:forward)
opt
opt.minimizerend
sim_θhat (generic function with 1 method)
Repeat \(R\) replications
= 250
num_obs = 500
num_rep # Initialize output
= Matrix(undef, length(θ₀), num_rep)
results for i in 1:num_rep
:, i] = sim_θhat(num_obs)
results[end
# Mean estimates
mean(results, dims = 2)
7×1 Matrix{Float64}:
0.0006639386137645048
0.9978489158537106
0.9454197504862293
0.20577261923685305
0.24026813468427904
1.0373020388366407
0.2070202636496464
Result table
= ["αᵢ", "αₛ", "ψᵢ", "ψᵢₛ", "ψₛ", "θ", "ρ"]
parnames = hcat(parnames,
results_tbl mean(results, dims = 2),
mean(results, dims = 2) .- θ₀)
print(markdown_table(Tables.table(results_tbl; header = [:Parameter, :Estimate, :Bias]), String))
Parameter | Estimate | Bias |
---|---|---|
αᵢ | 0.0006639386137645048 | 0.0006639386137645048 |
αₛ | 0.9978489158537106 | -0.002151084146289395 |
ψᵢ | 0.9454197504862293 | -0.05458024951377072 |
ψᵢₛ | 0.20577261923685305 | 0.005772619236853044 |
ψₛ | 0.24026813468427904 | -0.009731865315720956 |
θ | 1.0373020388366407 | 0.03730203883664074 |
ρ | 0.2070202636496464 | 0.007020263649646391 |
Plot
boxplot(repeat(parnames, outer = 500), vec(results .- θ₀), legend = false) Plots.