Monte Carlo Estimator Comparison

Context: FIT2086_MOC · Studio 3 · the empirical route to bias, variance and MSE when the algebra is hard or absent — simulate the sampling distribution and measure it · extends R Simulation and Random Sampling and R Toolkit (Cheatsheet) Problem it solves: decide which of two estimators of the same quantity is better, without deriving either one’s sampling distribution by hand.

Quick Revision

  • 🎯 Trigger: “which estimator is better”, “how does it behave as grows”, “what if the data are contaminated” ➔ loop niterations times: generate → estimate → store, then summarise the stored vectors.
  • ⚠️ Key Constraint: the loop’s mu argument is the true you compare against — bias is over iterations, so the simulation only works because you chose the population.

🔧 Minimal Working Example

mean_median_test <- function(niterations, mu, sigma, n, nc = 0) {
  mu_hat  = rep(0, niterations)      # PREALLOCATE — growing with c() is O(niter^2)
  med_hat = rep(0, niterations)
 
  for (i in 1:niterations) {
    y = rnorm(n, mu, sigma)                      # one fresh dataset per iteration
    if (nc > 0) y[1:nc] = rnorm(nc, mu, 4*sigma) # contaminate the first nc points
    mu_hat[i]  = mean(y)
    med_hat[i] = median(y)
  }
 
  retval = list()
  retval$bias_mean = mean(mu_hat - mu)                             # b_theta
  retval$var_mean  = var(mu_hat)                                   # Var_theta
  retval$mse_mean  = retval$bias_mean^2 + retval$var_mean          # MSE = b^2 + Var
  retval$bias_med  = mean(med_hat - mu)
  retval$var_med   = var(med_hat)
  retval$mse_med   = retval$bias_med^2 + retval$var_med
  retval$rel_mse   = retval$mse_mean / retval$mse_med              # < 1 ⟹ mean wins
  return(retval)
}
mean_median_test(1e4, mu = 0, sigma = 1, n = 10)

Expected output: a list with both biases , , , rel_mse . The exact theory for the mean is , , the simulation reproduces it to two decimals, which is how you validate the code before trusting the median column.

📊 Results — iterations,

Reading
clean data ➔ mean more efficient
both scale by RelMSE unchanged
mean’s variance falls by exactly , median’s by less ➔ gap widens for the mean
one contaminated point ➔ verdict flips to the median
worse still for the mean
more clean data dilutes the contamination ➔ back to parity
contaminate more and the median leads again

Final extracted output: neither estimator is biased in any row — the entire comparison lives in the variance. Efficiency favours the mean on clean normal data; robustness favours the median as soon as a fraction of the sample is drawn from a -wide contaminating distribution.

When It Flips: is the boundary. It is crossed by the contamination fraction , not by or alone — flips the verdict at but not at .

🔭 Beyond the lecture (not in the slides): for a normal population , so as — which is exactly the the row reports.

🔀 Variations

  • Sweep the sample size ➔ loop the whole study over n_vals <- seq(5, 100, by = 5), storing one summary per , then plot two panels side by side:
par(mfrow = c(1, 2))                                   # 1 row, 2 columns of plots
plot(n_vals, var_mean, type="l", col="blue", lwd=2, xlab="Sample size (n)", ylab="Variance")
lines(n_vals, var_median, col="red", lwd=2)
legend("topright", legend=c("Mean","Median"), col=c("blue","red"), lwd=2, bty="n")
plot(n_vals, rel_mse, type="l", col="purple", lwd=2, xlab="Sample size (n)", ylab="RelMSE")

Expected output: with both variance curves decay like with the mean’s strictly below, and RelMSE sits flat below ; with the mean’s curve starts far higher, RelMSE begins above and drifts down toward it as the contaminated fraction shrinks.

  • Default argumentnc = 0 in the signature keeps every earlier call valid after the function is extended — no call sites need editing.

✍️ Practice

⚠️ Common Mistakes

  • 💡 Growing the result vectors inside the loopmu_hat = c(mu_hat, mean(y)) reallocates every iteration (); rep(0, niterations) preallocates.
  • 💡 Computing bias against instead of mean(mu_hat - mean(mu_hat)) is identically and measures nothing; bias must be taken against the true parameter you simulated from.
  • 💡 Skipping the exact-value check ➔ always confirm the mean’s simulated first; if that fails, the code is wrong and the median’s numbers are meaningless.
  • 💡 Reading “median is more robust” as “median is better” ➔ on clean normal data the median throws away information and pays more MSE; robustness is only an advantage once contamination is actually present.
  • 💡 Forgetting var() uses the divisor ➔ that is the intended unbiased estimate of the sampling variance here, but it is not .