The Simulated Method of Moments (SMM) is a powerful estimation technique. It allows us to estimate parameters of a model by matching moments from simulated data to those from observed data.
SMM is particularly valuable in scenarios where:
The basic steps of SMM:
Let’s see a super super super basic example in R. We’ll build from here.
library(stats)
# Step 1: Define the true parameters (unknown in real applications)
true_mean <- 5
true_sd <- 2
# Generate observed data
set.seed(123)
observed_data <- rnorm(1000, mean = true_mean, sd = true_sd)
# Step 2: Choose moments to match (mean and variance)
observed_moments <- c(mean(observed_data), var(observed_data))
# Step 3 & 4: Function to simulate data and calculate moments
simulate_moments <- function(params, n = 1000) {
simulated_data <- rnorm(n, mean = params[1], sd = params[2])
c(mean(simulated_data), var(simulated_data))
}
# Step 5: Objective function
objective <- function(params) {
sim_moments <- simulate_moments(params)
sum((sim_moments - observed_moments)^2)
}
# Step 6: Minimize the objective function
result <- optim(par = c(0, 1), fn = objective, method = "L-BFGS-B", lower = c(-Inf, 0.01), upper = c(Inf, Inf))
# Print results
cat("Estimated mean:", result$par[1], "\n")
cat("Estimated sd:", result$par[2], "\n")
cat("True mean:", true_mean, "\n")
cat("True sd:", true_sd, "\n")
In actual applications of the SMM, researchers use a two-step optimization with optimal weighting matrix. This is a summary of how the procedure looks like:
Let’s draft an example code in R to make this more concrete.
library(MASS) # for mvrnorm function
library(numDeriv) # for gradient and hessian calculations
# True parameters (unknown in real applications)
true_params <- c(mean = 5, sd = 2)
# Generate observed data
set.seed(123)
observed_data <- rnorm(1000, mean = true_params[1], sd = true_params[2])
# Calculate observed moments (mean and variance)
observed_moments <- c(mean(observed_data), var(observed_data))
# Function to simulate moments
simulate_moments <- function(params, n = 1000) {
simulated_data <- rnorm(n, mean = params[1], sd = params[2])
c(mean(simulated_data), var(simulated_data))
}
# Objective function
objective <- function(params, W) {
sim_moments <- simulate_moments(params)
diff <- sim_moments - observed_moments
t(diff) %*% W %*% diff
}
# Two-step SMM estimation
smm_two_step <- function(initial_params) {
# Step 1: Initial estimation with identity matrix
step1 <- optim(par = initial_params, fn = objective, W = diag(2),
method = "L-BFGS-B", lower = c(-Inf, 0.01))
# Compute optimal weighting matrix
S <- cov(replicate(1000, simulate_moments(step1$par) - observed_moments))
W_optimal <- solve(S)
# Step 2: Re-estimate with optimal weighting matrix
step2 <- optim(par = step1$par, fn = objective, W = W_optimal,
method = "L-BFGS-B", lower = c(-Inf, 0.01))
return(list(params = step2$par, W = W_optimal))
}
# Run two-step SMM
result <- smm_two_step(c(0, 1))
print(result$params)
To estimate standard errors, bootstraps are often a good idea. This involves resampling our observed data, re-estimating the parameters, and calculating the standard deviation of these estimates. Let’s see how that may look like:
# Bootstrapping function
bootstrap_smm <- function(n_bootstrap = 1000) {
bootstrap_estimates <- matrix(NA, nrow = n_bootstrap, ncol = 2)
for (i in 1:n_bootstrap) {
# Resample observed data
boot_data <- sample(observed_data, replace = TRUE)
boot_moments <- c(mean(boot_data), var(boot_data))
# Define bootstrap objective function
boot_objective <- function(params, W) {
sim_moments <- simulate_moments(params)
diff <- sim_moments - boot_moments
t(diff) %*% W %*% diff
}
# Run SMM on bootstrap sample
boot_result <- optim(par = result$params, fn = boot_objective, W = result$W,
method = "L-BFGS-B", lower = c(-Inf, 0.01))
bootstrap_estimates[i,] <- boot_result$par
}
# Calculate standard errors
se <- apply(bootstrap_estimates, 2, sd)
return(se)
}
# Run bootstrap
bootstrap_se <- bootstrap_smm()
# Print results
cat("Estimated parameters:\n")
print(result$params)
cat("\nBootstrap standard errors:\n")
print(bootstrap_se)
cat("\nTrue parameters:\n")
print(true_params)
Now, some practical considerations.
Remember, the key to successful SMM implementation lies in careful model specification, thoughtful moment selection, and robust optimization techniques. Happy simulation!