Code
[1] 0.0000 0.0131 0.9086 0.8102 0.2842
Random Numbers and Elementary Monte Carlo
2026-09-24
A computer is deterministic, so it cannot produce truly random numbers. It produces pseudo random numbers: a deterministic sequence that behaves like iid \mathrm{Unif}(0,1) draws.
A classic generator, the linear congruential generator (LCG): x_{i+1} = (a\,x_i + c) \bmod m, \qquad u_{i+1} = x_{i+1}/m
The starting value x_0 is the seed. The same seed gives the same sequence, which makes simulations reproducible.
The sequence eventually repeats; a good generator has a very long period and passes statistical tests of uniformity and independence.
R’s default is the Mersenne Twister (period 2^{19937}-1). All other distributions in R are built from \mathrm{Unif}(0,1) draws.
The trace shows no visible trend, drift, or periodicity, and the points fill (0,1) without clustering. This is what “behaves like iid uniform” means in practice, though a convincing assessment requires formal tests of uniformity and serial correlation rather than a single plot of 50 values.
[1] 0.2655087 0.3721239 0.5728534
[1] 0.2655087 0.3721239 0.5728534
[1] 0.9082078 0.2016819 0.8983897
Always set.seed() at the top of a simulation study so results can be reproduced and debugged.
If U \sim \mathrm{Unif}(0,1) then X = a + (b-a)\,U \sim \mathrm{Unif}(a,b): P(X \le x) = P\!\left(U \le \frac{x-a}{b-a}\right) = \frac{x-a}{b-a}, \qquad a \le x \le b .
Let F_X be a continuous CDF with inverse (quantile function) F_X^{-1}.
Theorem. If U \sim \mathrm{Unif}(0,1), then X = F_X^{-1}(U) has CDF F_X.
Proof.. P(X \le x) = P\big(F_X^{-1}(U) \le x\big) = P\big(U \le F_X(x)\big) = F_X(x).
Equivalently, by the change-of-variable formula with u = F_X(x): f_X(x) = f_U\big(F_X(x)\big)\left\lvert\frac{du}{dx}\right \rvert = 1 \times f(x).
The converse also holds: if X \sim F_X then F_X(X) \sim \mathrm{Unif}(0,1) (the probability integral transform), which we will use for p-values.
Draw u on the vertical axis, read x = F^{-1}(u) off the horizontal axis. Regions where F is steep (high density) receive more draws.
X \sim \mathrm{Exp}(\lambda) has F_X(x) = 1 - e^{-\lambda x} for x > 0. Solving u = 1 - e^{-\lambda x}: x = F_X^{-1}(u) = -\frac{1}{\lambda}\log(1-u).
Since 1 - U \sim \mathrm{Unif}(0,1) as well, we may use X = -\log(U)/\lambda.
\Phi^{-1} has no closed form, so the inverse-CDF method is not directly usable. Instead, look at a pair (Z_1, Z_2) \overset{iid}{\sim} N(0,1) in polar coordinates: Z_1 = R\cos\Theta, \qquad Z_2 = R\sin\Theta, \qquad R^2 = Z_1^2 + Z_2^2, \quad \Theta = \operatorname{atan2}(Z_2, Z_1).
The joint density \frac{1}{2\pi}e^{-(z_1^2+z_2^2)/2} depends on (z_1, z_2) only through r^2 = z_1^2 + z_2^2, so it is rotationally symmetric about the origin. Consequently:
The angle \Theta \sim \mathrm{Unif}(0, 2\pi), independent of R.
The squared radius R^2 = Z_1^2 + Z_2^2 \sim \chi^2_2, and \chi^2_2 is the exponential distribution with rate 1/2: f_{\chi^2_2}(w) = \frac{1}{2}e^{-w/2}, \quad w > 0 \qquad\Longrightarrow\qquad R^2 \sim \mathrm{Exp}(\text{rate} = 1/2).
Both R^2 and \Theta can be generated by inverting a CDF.
The point cloud is rotationally symmetric: the red circles enclose 50%, 90%, 99% of the points (R^2 \le \chi^2_2 quantiles); the angle is uniform; R^2 follows \mathrm{Exp}(1/2).
Reverse the picture: generate R^2 and \Theta, then rotate back to (Z_1, Z_2).
R^2 \sim \mathrm{Exp}(1/2) by inverse CDF: F(w) = 1 - e^{-w/2}, so R^2 = -2\log U_1, i.e. R = \sqrt{-2\log U_1}.
\Theta \sim \mathrm{Unif}(0, 2\pi): \Theta = 2\pi U_2.
Z_1 = R\cos\Theta, Z_2 = R\sin\Theta.
Theorem (Box–Muller). If U_1, U_2 \overset{iid}{\sim} \mathrm{Unif}(0,1), then. Z_1 = \sqrt{-2\log U_1}\,\cos(2\pi U_2), \qquad Z_2 = \sqrt{-2\log U_1}\,\sin(2\pi U_2), are independent N(0,1). Two uniforms produce two normals. Then \mu + \sigma Z \sim N(\mu, \sigma^2).
box_muller <- function(n) {
u1 <- runif(n); u2 <- runif(n)
r <- sqrt(-2 * log(u1)) # R^2 ~ Exp(1/2), i.e. chi-square(2)
th <- 2 * pi * u2 # Theta ~ Unif(0, 2 pi)
cbind(z1 = r * cos(th), z2 = r * sin(th))
}
z <- box_muller(3000)
par(mfrow = c(1, 2), mar = c(4, 4, 2, 1))
par(pty = "s"); plot(z, pch = 20, cex = 0.4, col = "grey40", asp = 1, main = "Box-Muller output")
par(pty = "m"); qqnorm(c(z), pch = ".", main = "Normal Q-Q plot of both coordinates"); qqline(c(z), col = 2) mean sd corr
-0.02673691 0.98937455 0.02537785
Monte Carlo estimates an expectation \mu = E(g(X)) by an average of simulated values, \hat\mu_n = \frac{1}{n}\sum_{i=1}^n g(X_i), \qquad X_i \overset{iid}{\sim} f .
Theorem (Strong Law of Large Numbers). If X_1, X_2, \ldots are iid with finite mean \mu, then. P\left(\frac{X_1 + \cdots + X_n}{n} \to \mu\right) = 1 .
The LLN guarantees that the average converges to the truth. It does not say how fast.
Theorem (Central Limit Theorem). If in addition the variance \sigma^2 is finite, then \frac{\overline X - \mu}{\sigma/\sqrt n} \;\xrightarrow{d}\; N(0,1).
The CLT gives the error bound: the Monte Carlo error is of order \sigma/\sqrt n.
From (5.2), with confidence level 95%, P\!\left(\lvert\overline X - \mu \rvert \le 1.96\,\frac{\sigma}{\sqrt n}\right) \approx 0.95, so a 95% interval for \mu is \overline X \pm 1.96\,\frac{\sigma}{\sqrt n}, \qquad \sigma \text{ replaced by the sample SD } s .
Halving the error requires four times as many samples; each extra decimal digit of accuracy costs a 100-fold increase in n.
The rate n^{-1/2} does not depend on the dimension of X, which is why Monte Carlo beats numerical quadrature in high dimensions.
Running averages of X_i \sim \mathrm{Exp}(1) (\mu = 1) for three independent sequences:
For each of N = 5000 repetitions, draw n values from \mathrm{Exp}(1) and standardize the mean, (\overline X - 1)/(1/\sqrt n):
The skewed exponential becomes approximately normal as n grows.
Let (X, Y) be uniform on the square S = (-1,1)\times(-1,1), and let C = \{(x,y): x^2 + y^2 \le 1\} be the unit disk. Then. P\big((X,Y) \in C\big) = \frac{\text{area}(C)}{\text{area}(S)} = \frac{\pi}{4}.
Define Z = 4\, I\big((X,Y)\in C\big), so E(Z) = \pi and \mathrm{Var}(Z) = 16 \cdot \frac{\pi}{4}\left(1 - \frac{\pi}{4}\right) \approx 2.70, \qquad \mathrm{SD}(Z) \approx 1.64 .
Drawing (X_i, Y_i) and averaging Z_i: \hat\pi_n = \frac{1}{n}\sum_{i=1}^n Z_i = 4 \times \frac{\# \{i: X_i^2 + Y_i^2 \le 1\}}{n}.
n <- 2000; x <- runif(n, -1, 1); y <- runif(n, -1, 1); inside <- x^2 + y^2 <= 1
par(pty = "s")
plot(x, y, col = ifelse(inside, "steelblue", "grey60"), pch = 20, cex = 0.6,
main = sprintf("n = %d, proportion inside = %.3f, pi-hat = %.3f", n, mean(inside), 4 * mean(inside)))
curve(sqrt(1 - x^2), -1, 1, add = TRUE, lwd = 2); curve(-sqrt(1 - x^2), -1, 1, add = TRUE, lwd = 2) estimate se
3.12840000 0.01651359
[1] 3.096033 3.160767
The standard error s/\sqrt n is computed from the same simulated values — no extra cost. Always report it with a Monte Carlo estimate.
n estimate error se theory_se
1 1e+02 3.12000 -0.02159 0.16700 0.16400
2 1e+03 3.21600 0.07441 0.05020 0.05190
3 1e+04 3.14280 0.00121 0.01640 0.01640
4 1e+05 3.14260 0.00101 0.00519 0.00519
5 1e+06 3.14188 0.00029 0.00164 0.00164
The observed error is typically within about 2 standard errors.
SE shrinks by \sqrt{10} \approx 3.2 for each 10-fold increase in n, as the CLT predicts.
set.seed(1)
n <- 1e5; z <- 4 * (runif(n, -1, 1)^2 + runif(n, -1, 1)^2 <= 1)
k <- 1:n; pihat <- cumsum(z) / k
par(mar = c(4, 4.5, 0.5, 0.5), mgp = c(2.5, 0.8, 0))
plot(k, pihat, type = "l", log = "x", ylim = c(2, 4),
xlab = "n (log scale)", ylab = expression(hat(pi)[n]))
lines(k, pi + 1.96 * 1.64 / sqrt(k), lty = 2, col = 2)
lines(k, pi - 1.96 * 1.64 / sqrt(k), lty = 2, col = 2)
abline(h = pi, col = 4)The red band is \pi \pm 1.96\,\sigma/\sqrt n; the running estimate stays inside it most of the time.
A point estimator \hat\theta = \hat\theta(X_1, \ldots, X_n) is judged by its mean squared error \mathrm{MSE}(\hat\theta) = E\big[(\hat\theta - \theta)^2\big] = \mathrm{Var}(\hat\theta) + \big[\mathrm{Bias}(\hat\theta)\big]^2 .
MSE is an expectation, so it is estimated by Monte Carlo: simulate N independent data sets from a model with known \theta, \hat\theta^{(j)} = \hat\theta\big(X_1^{(j)}, \ldots, X_n^{(j)}\big), \qquad j = 1, \ldots, N, and compute \widehat{\mathrm{MSE}} = \frac{1}{N}\sum_{j=1}^N \big(\hat\theta^{(j)} - \theta\big)^2, \qquad \widehat{\mathrm{Bias}} = \overline{\hat\theta} - \theta, \qquad \widehat{\mathrm{Var}} = \frac{1}{N}\sum_{j=1}^N \big(\hat\theta^{(j)} - \overline{\hat\theta}\big)^2 .
Two sample sizes appear: n (data per replicate, fixed by the problem) and N (replicates, chosen large enough that the Monte Carlo error is negligible).
Estimating the centre \theta = 0 of a symmetric distribution, n = 20, N = 5000 replicates.
mean median trim10
bias 0.0010 0.0019 0.0013
var 0.0489 0.0738 0.0514
mse 0.0489 0.0738 0.0514
mean median trim10
bias -0.0089 -0.0031 -0.0040
var 0.1438 0.0912 0.0847
mse 0.1438 0.0912 0.0847
No estimator is best everywhere: the mean wins under normality, the trimmed mean and median win under heavy tails.
A test rejects H_0 when a statistic T exceeds a critical value c_\alpha.
| reject: T > c_\alpha | do not reject: T \le c_\alpha | |
|---|---|---|
| H_0 true | Type I error (false positive) | true negative |
| H_1 true | true positive | Type II error (false negative) |
\text{size} = P(T > c_\alpha \mid H_0) = \alpha, \qquad \text{power} = P(T > c_\alpha \mid H_1) = 1 - \beta .
Both are probabilities — hence expectations of indicators — so both can be estimated by Monte Carlo once we can simulate data under H_0 and H_1.
For a test that rejects when T > c, simulate N data sets under H_0 and N data sets under H_1, and compute T on each:
| replicate | T^{(j)}_{H_0} | I(T^{(j)}_{H_0} > c) | T^{(j)}_{H_1} | I(T^{(j)}_{H_1} > c) |
|---|---|---|---|---|
| 1 | T^{(1)}_{H_0} | 0 | T^{(1)}_{H_1} | 1 |
| 2 | T^{(2)}_{H_0} | 1 | T^{(2)}_{H_1} | 1 |
| \vdots | \vdots | \vdots | \vdots | \vdots |
| N | T^{(N)}_{H_0} | 0 | T^{(N)}_{H_1} | 0 |
\widehat{\text{FPR}}(c) = \frac{1}{N}\sum_{j=1}^N I\big(T^{(j)}_{H_0} > c\big), \qquad \widehat{\text{TPR}}(c) = \frac{1}{N}\sum_{j=1}^N I\big(T^{(j)}_{H_1} > c\big).
\widehat{\text{FPR}} estimates the size (type I error rate); \widehat{\text{TPR}} estimates the power, 1 - \beta.
To get size \alpha, take \hat c_\alpha = the (1-\alpha) sample quantile of T^{(1)}_{H_0}, \ldots, T^{(N)}_{H_0}, which replaces the (often unknown) null distribution of T by its empirical distribution.
The p-value is the probability, under H_0, of a statistic at least as extreme as the observed one: \text{p-value}(t) = P(T \ge t \mid H_0) = 1 - F_{H_0}(t), the survival function of T under H_0 evaluated at t^{obs}. Rejecting when \text{p-value}(t^{obs}) < \alpha is the same as rejecting when t^{obs} > c_\alpha.
Theorem. If T \mid H_0 has continuous CDF F_{H_0}, then \text{p-value}(T) = 1 - F_{H_0}(T) \sim \mathrm{Unif}(0,1) under H_0.
Proof. For t \in (0,1), \begin{aligned} P\big(\text{p-value}(T) < t\big) &= P\big(1 - F_{H_0}(T) < t\big) = P\big(F_{H_0}(T) > 1 - t\big) \\ &= P\big(T > F_{H_0}^{-1}(1-t)\big) = 1 - F_{H_0}\big(F_{H_0}^{-1}(1-t)\big) = t . \end{aligned}
Consequences:
P(\text{p-value} < \alpha \mid H_0) = \alpha exactly: rejecting when \text{p-value} < \alpha has size \alpha.
A histogram of simulated p-values under H_0 should be flat — the standard test of a test.
t.testOne-sample t-test of H_0: \mu = 0, n = 20, N = 5000:
pv_sim <- function(mu, n = 20, N = 5000) replicate(N, t.test(rnorm(n, mu))$p.value)
pv0 <- pv_sim(0); pv1 <- pv_sim(0.5)
par(mfrow = c(1, 2), mar = c(4, 4, 2, 1))
hist(pv0, breaks = 20, main = expression(H[0]: mu == 0), xlab = "p-value"); abline(h = 250, col = 2, lty = 2)
hist(pv1, breaks = 20, main = expression(H[1]: mu == 0.5), xlab = "p-value")Under H_0 the p-values are uniform; under H_1 they pile up near 0.
\widehat{\text{size}} = \hat P(\text{p-value} < \alpha \mid H_0) = \frac{1}{N}\sum_{j=1}^N I\big(\text{p-value}^{(j)}_{H_0} < \alpha\big), \widehat{\text{power}} = \hat P(\text{p-value} < \alpha \mid H_1) = \frac{1}{N}\sum_{j=1}^N I\big(\text{p-value}^{(j)}_{H_1} < \alpha\big)
size power exact_power
0.0450000 0.5550000 0.5644829
Each estimate is a proportion, so its Monte Carlo standard error is \sqrt{\hat p(1-\hat p)/N} — about 0.003 for the size with N = 5000.
When F_{H_0} is unknown, estimate \text{p-value}(t^{obs}) by simulating T under H_0: \widehat{\text{p-value}}(t^{obs}) = \frac{1 + \sum_{j=1}^N I\big(T^{(j)} \ge t^{obs}\big)}{N + 1}.
(The “+1” counts the observed statistic as one draw from H_0; it keeps the estimate above 0 and the test exactly valid.)
Example: test H_0: \mu = 0 for n = 15 observations using T = \lvert\overline X \rvert/(s/\sqrt n), but suppose we did not know the t-distribution.
Data (X_i, Y_i), i = 1, \ldots, n. Test H_0: X \perp Y (which implies \mathrm{corr}(X,Y) = 0) with T = \lvert\hat\rho \rvert.
Under H_0, every pairing of the X values with the Y values is equally likely, so the null distribution of T is obtained by re-computing T after randomly permuting Y:
Compute \rho^{obs} = \hat\rho(X, Y).
For j = 1, \ldots, m: permute Y to get Y^{(j)}, compute \rho^{(j)} = \hat\rho(X, Y^{(j)}).
\widehat{\text{p-value}} = \dfrac{1 + \# \{j : \lvert\rho^{(j)} \rvert \ge \lvert\rho^{obs} \rvert\}}{m+1}.
No normality assumption is needed; the null distribution is generated from the data itself.
X is held fixed; each of the m permutations re-shuffles the Y column (shown for n = 5):
| X | observed Y | Y^{(1)} | Y^{(2)} | \cdots | Y^{(m)} | |
|---|---|---|---|---|---|---|
| i = 1 | x_1 | y_1 | y_3 | y_5 | \cdots | y_2 |
| i = 2 | x_2 | y_2 | y_1 | y_4 | \cdots | y_5 |
| i = 3 | x_3 | y_3 | y_5 | y_1 | \cdots | y_4 |
| i = 4 | x_4 | y_4 | y_2 | y_3 | \cdots | y_1 |
| i = 5 | x_5 | y_5 | y_4 | y_2 | \cdots | y_3 |
| statistic | \rho^{obs} | \rho^{(1)} | \rho^{(2)} | \cdots | \rho^{(m)} | |
| as extreme? | I(\lvert\rho^{(1)}\rvert \ge \lvert\rho^{obs}\rvert) | I(\lvert\rho^{(2)}\rvert \ge \lvert\rho^{obs}\rvert) | \cdots | I(\lvert\rho^{(m)}\rvert \ge \lvert\rho^{obs}\rvert) |
\rho^{(1)}, \ldots, \rho^{(m)} are draws from the null distribution of \hat\rho. The p-value is 1 plus the sum of the last row, divided by m + 1.
Generate non-normal (X, Y): independent under H_0, and Y = 0.4X + \epsilon under H_1. Check that the permutation p-values are uniform with size \alpha under H_0, and estimate the power under H_1.
| dataset | data under H_0 (or H_1) | \rho^{obs} | permutation test | p-value | reject? |
|---|---|---|---|---|---|
| k = 1 | (X^{[1]}, Y^{[1]}) | \rho^{obs}_{1} | m permutations of Y^{[1]} | pv_1 | I(pv_1 < \alpha) |
| k = 2 | (X^{[2]}, Y^{[2]}) | \rho^{obs}_{2} | m permutations of Y^{[2]} | pv_2 | I(pv_2 < \alpha) |
| \vdots | \vdots | \vdots | \vdots | \vdots | \vdots |
| k = N | (X^{[N]}, Y^{[N]}) | \rho^{obs}_{N} | m permutations of Y^{[N]} | pv_N | I(pv_N < \alpha) |
| summary | histogram | \widehat{\text{size}} (or \widehat{\text{power}}) = \frac{1}{N}\sum_k I(pv_k < \alpha) |
Below, N = 500 and m = 500.
sim_cor <- function(n = 30, b = 0) { x <- rexp(n); list(x = x, y = b * x + rexp(n)) }
eval_perm_cor <- function(b, N = 500) replicate(N, {
d <- sim_cor(b = b)
perm_cor_test(d$x, d$y, m = 500)$pv
})
pv_cor0 <- eval_perm_cor(b = 0) # H0: independent
pv_cor1 <- eval_perm_cor(b = 0.4) # H1: dependent
hist_reject <- function(pv, main, alpha = 0.05) {
br <- seq(0, 1, by = alpha) # first bar = rejection region
ymax <- max(hist(pv, breaks = br, plot = FALSE)$counts)
hist(pv, breaks = br, main = main, xlab = "p-value",
ylim = c(0, 1.3 * ymax), # headroom for the legend
col = ifelse(br[-1] <= alpha, "red", "grey80"))
abline(v = alpha, col = "red", lwd = 2, lty = 2)
legend("topright", bty = "n", fill = c("red", NA), border = c("black", NA),
lty = c(NA, 2), col = c(NA, "red"), lwd = c(NA, 2),
legend = c(sprintf("rejected: %.3f", mean(pv < alpha)),
as.expression(bquote(alpha == .(alpha)))))
}
par(mfrow = c(1, 2))
hist_reject(pv_cor0, "permutation p-values under H0")
hist_reject(pv_cor1, "permutation p-values under H1")Under H_0 the permutation p-values are uniform on [0,1] and the size is close to 0.05, with no distributional assumption on (X, Y). Under H_1 they pile up near 0; the proportion below 0.05 is the power.
Response Y and p = 20 candidate predictors X_1, \ldots, X_{20}, n = 50. We want to test H_0: Y is unrelated to all of the X’s.
A common practice:
Pick the predictor X_{k^*} most correlated with Y.
Fit Y \sim X_{k^*} and report the usual t-test p-value for its slope.
Question. Is this a valid test of H_0? Does it have size \alpha?
The t-test p-value assumes X_{k^*} was chosen in advance. Selecting the best of 20 predictors after looking at the data means that, even under H_0, \max_k \lvert\hat\rho_k \rvert tends to be large. The reported p-value ignores this selection.
test_lm_selSimulate N = 2000 datasets with Y = \beta X_1 + \epsilon: \beta = 0 under H_0, and \beta = 0.5 under H_1.
sim_lm <- function(n = 50, p = 20, beta = 0) {
X <- matrix(rnorm(n * p), n, p); list(y = beta * X[, 1] + rnorm(n), X = X)
}
pv_sel0 <- replicate(2000, { d <- sim_lm(beta = 0); test_lm_sel(d$y, d$X) })
pv_sel1 <- replicate(2000, { d <- sim_lm(beta = 0.5); test_lm_sel(d$y, d$X) })
par(mfrow = c(1, 2))
hist_reject(pv_sel0, "test_lm_sel p-values under H0")
hist_reject(pv_sel1, "test_lm_sel p-values under H1")The true size is far above 0.05: test_lm_sel rejects a true H_0 far too often. Under H_0 its p-value is not uniform, which is a general diagnostic for an invalid test. Its high rejection rate under H_1 is not real power, since the test does not have size \alpha.
Fix: repeat the whole procedure — select the most correlated variable, fit the linear model, report its p-value — on permuted responses, and compare the observed p-value with the permutation distribution of p-values.
Compute p^{obs} = p-value of test_lm_sel on (Y, X).
For j = 1, \ldots, m: permute Y, compute p^{(j)} = p-value of test_lm_sel on (Y^{(j)}, X) (re-doing the selection each time).
\widehat{\text{p-value}} = \dfrac{1 + \# \{j : p^{(j)} \le p^{obs}\}}{m+1}, the proportion of permuted p-values at least as small as the observed one.
k^*(Y) = \arg\max_k \lvert\hat\rho(X_k, Y)\rvert is the index of the column of X most correlated with the response. It is a function of the response, so each permuted Y^{(j)} gets its own selected predictor X_{k^*(Y^{(j)})}:
Keeping X_{k^*(Y)} fixed and only permuting Y would not reproduce the selection step, and the resulting test would still be invalid.
Simulate (Y, X) from sim_lm: \beta = 0 under H_0, and \beta = 0.5 under H_1. Check that the permutation p-values are uniform with size \alpha under H_0, and estimate the power under H_1.
| dataset | data under H_0 (or H_1) | p^{obs} | permutation test | p-value | reject? |
|---|---|---|---|---|---|
| k = 1 | (Y^{[1]}, X^{[1]}) | p^{obs}_{1} | m permutations of Y^{[1]} | pv_1 | I(pv_1 < \alpha) |
| k = 2 | (Y^{[2]}, X^{[2]}) | p^{obs}_{2} | m permutations of Y^{[2]} | pv_2 | I(pv_2 < \alpha) |
| \vdots | \vdots | \vdots | \vdots | \vdots | \vdots |
| k = N | (Y^{[N]}, X^{[N]}) | p^{obs}_{N} | m permutations of Y^{[N]} | pv_N | I(pv_N < \alpha) |
| summary | histogram | \widehat{\text{size}} (or \widehat{\text{power}}) = \frac{1}{N}\sum_k I(pv_k < \alpha) |
Below, N = 300 and m = 500.
eval_perm_lm_sel <- function(beta, N = 300) replicate(N, {
d <- sim_lm(beta = beta)
perm_lm_sel(d$y, d$X, m = 500)
})
pv_perm0 <- eval_perm_lm_sel(beta = 0) # H0: Y unrelated to X
pv_perm1 <- eval_perm_lm_sel(beta = 0.5) # H1: Y depends on X1
par(mfrow = c(1, 2))
hist_reject(pv_perm0, "perm_lm_sel p-values under H0")
hist_reject(pv_perm1, "perm_lm_sel p-values under H1")Under H_0 the permutation p-values are uniform and the size is close to 0.05; under H_1 they pile up near 0, and the proportion below 0.05 is an honest power.
All simulation starts from pseudo-random \mathrm{Unif}(0,1) draws; other distributions come from inverse-CDF or transformations (Box–Muller).
The LLN justifies Monte Carlo averages; the CLT gives their error, \sigma/\sqrt n, which is reported as a standard error.
Bias, variance and MSE of estimators, and size and power of tests, are expectations — simulate with known truth and average.
P-values are uniform under H_0: a flat histogram of simulated p-values is the basic test of a test.
When the null distribution is unknown, generate it by simulation or by permutation; the permuted statistic must reproduce the entire data-analysis procedure.