[1] 0.63
Lab 4
October 30, 2026
Today’s goals. Learn about:
Workflow
Let’s start
The likelihood function
Let \(\mathcal{F}\) be a parametric statistical model for the data \(y\), where \(f(y;\theta)\) is the density or probability function and \(\theta \in \Theta\) is a p-dimensional parameter. By considering \(f(y;\theta)\) as function of \(\theta\) with \(y\) fixed to the observed value, then the likelihood function of \(\theta\) based on \(y\), \(L: \Theta \rightarrow \mathbb{R}^{+}\), is \[L(\theta) = L(\theta; y) \propto f_Y(y; \theta) \,\,, \] where the proportionality is related to a constant \(c(y)>0\) that does not depend on \(\theta\).
On the basis of the data \(y\), \(\theta \in \Theta\) is more likely than \(\theta' \in \Theta\) as an index of the data generating model if \(L(\theta) > L(\theta')\)
Note
Setup
R functions for numerical optimisation
In the Binomial example, the MLE is available in closed form and we obtain numerical values just by plugging the data into the formula. However, remember that the MLE for a parameter may not have an analytic solution. Many times we do not have a closed form for MLE estimates and we may need numerical optimisation. R provides various functions for performing numerical methods:
nlm(): minimizes a function using a Newton-type algorithm. It needs a starting value and does not allow constraints on the parameters. It is usually fast and reliable. It returns the ML estimate \(\hat{\theta}\) (estimate), the minimum \(-\ell(\hat{\theta})\) of the negative log-likelihood (minimum) and the hessian (hessian), if hessian = TRUE.
optim(): minimizes a function using Nelder-Mead, quasi-Newton and conjugate gradients algorithms. It includes an option for box-constrained optimization, and it requires a starting value. It returns the ML estimate \(\hat{\theta}\) (par), the minimum of the negative log-likelihood \(-\ell(\hat{\theta})\) (value) and the hessian (hessian), if hessian = TRUE. You also can maximize the function by using fnscale = -1 in control argument.
nlminb(): often is more stable, robust and reliable than optim (in particular with “nasty” functions). It performs only minimization and does not yield numerical derivatives as output. It returns the ML estimate \(\hat{\theta}\) (par) and the minimum of the negative log-likelihood \(-\ell(\hat{\theta})\) (objective).
optimize(): by using a combination of golden section search and successive parabolic interpolation, searches in an interval for a minimum or a maximum (if maximum=TRUE) of a function. It returns \(\hat{\theta}\) (maximum if maximum=TRUE, otherwise minimum) and the value of the function there (objective). Drawback: suited only for one-dimensional parameter.
Binomial example
Here, we are simply using the Binomial example to show how (some of) these functions work.
Note: In the following, we consider and implement the negative log-likelihood function, since some numerical optimisers that we will see are only able to perform minimisation of functions.
In addition, we implement the score and the observed information (used for comparison with the optimiser output)
Binomial example
To check if the score and the observed information are correctly implemented, we can compute the numerical gradient and hessian of the log-likelihood function, as implemented in the {numDeriv} R package.
Important
Note that in this case, we obtain them for the negative log-likelihood function, implying that we need to change sign to the score function.
nlm optimiser
Let’s start with the first optimiser nlm (considering as starting value 0.5, which is quite close to the MLE; however, see the warnings printed in the R console)
$minimum
[1] 65.89557
$estimate
[1] 0.6299995
$gradient
[1] 1.421085e-08
$hessian
[,1]
[1,] 429.0957
$code
[1] 1
$iterations
[1] 5
[1] 65.89557
[1] 429
optim optimiser
The previous optimiser does not allow constraints on the parameters; however, there are some replacements in the algorithm that allow you to reach the result. If you want to optimise a function with constrained parameters, it is better to use an optimiser allowing for box-constrained optimisation, as for instance optim.
bin.optim_start1 <- optim(par = 0.5, fn = nllik_bin, hessian = TRUE,
data = y, method = "L-BFGS-B", lower = 1e-7, upper = 1-1e-7)
bin.optim_start1$par
[1] 0.6299996
$value
[1] 65.89557
$counts
function gradient
7 7
$convergence
[1] 0
$message
[1] "CONVERGENCE: REL_REDUCTION_OF_F <= FACTR*EPSMCH"
$hessian
[,1]
[1,] 429.0048
bin.optim_start2 <- optim(par = 0.001, fn = nllik_bin,
data = y, method = "L-BFGS-B", lower = 1e-7, upper =1-1e-7)
bin.optim_start2$par
[1] 0.6299996
$value
[1] 65.89557
$counts
function gradient
12 12
$convergence
[1] 0
$message
[1] "CONVERGENCE: REL_REDUCTION_OF_F <= FACTR*EPSMCH"
[,1]
[1,] 429.0048
Note
The optim() function provides a lot of numerical methods (Nelder-Mead, quasi-Newton, conjugate-gradient methods and simulated annealing). As a drawback, the user has to set up carefully the initial guesses and the method, since the final solution may be quite sensitive to these choices…To compute the observed information, the function optimHess() computes numerical derivatives of generic functions.
As an alternative, we could consider again the reparametrisation introduced above. Generally, for numerical purposes, it is convenient to reparameterize the model in such a way that the new parameter space is unbounded. Then, we explore this by using nlm()
$minimum
[1] 65.89557
$estimate
[1] 0.5322163
$gradient
[1] 2.842171e-08
$hessian
[,1]
[1,] 23.3094
$code
[1] 1
$iterations
[1] 4
[1] 65.89557
[1] 0.5322163 0.5322147 0.5322168
[,1]
[1,] 23.31
The model
rexp(n, rate = 1/theta))Individual predictions (write your answer before touching R)
1a. Plot the log-likelihood minus its maximum, over \(\theta \in (2, 20)\)
ll_exp <- function(theta, n, S) -n * log(theta) - S / theta
th <- seq(2, 20, length.out = 400)
lln <- sapply(th, ll_exp, n = n, S = S)
plot(th, lln - max(lln), type = "l", lwd = 2, xlab = expression(theta),
ylab = expression(l(theta) - max(l)))
## add a vertical line at the MLE (find it from the plot, then check in 1b)
TODOll_exp <- function(theta, n, S) -n * log(theta) - S / theta
th <- seq(2, 20, length.out = 400)
lln <- sapply(th, ll_exp, n = n, S = S)
plot(th, lln - max(lln), type = "l", lwd = 2, xlab = expression(theta),
ylab = expression(l(theta) - max(l)))
## add a vertical line at the MLE (find it from the plot, then check in 1b)
abline(v = mean(y), col = 2, lty = 2)1b. MLE: numerical maximisation vs the closed form
optimize() with maximum = TRUE maximises the log-likelihood directly1c. How much more supported is \(\theta = 5\) than \(\theta = 10\)?
Q1
How many times is \(\theta = 5\) more supported than \(\theta = 10\)? Is it a lot?
1d. Another sample with the SAME \(n\) and the SAME sum, different values
ll_exp for the two samples at \(\theta = 3, 5, 8\). What do you notice?Q2
What does 1d tell you about the data needed to build the likelihood? Link it to sufficient statistics (factorization in the slides).
1e. Derive \(U(\theta)\) and \(J(\theta)\) by hand from ll_exp and code them
Q3
Why is the score 0 at the MLE? Is the log-likelihood symmetric (P1)?
Simulation setup
Y is one sample)set.seed(2026)
R <- 10000; theta_t <- 5
Y <- matrix(rexp(n * R, rate = 1 / theta_t), nrow = R) # each row = one sample
Ssim <- rowSums(Y)
U_t <- U(theta_t, n, Ssim)
J_t <- J(theta_t, n, Ssim)
c(mean(U_t), var(U_t)) # expected score; variance of the score[1] -0.001857266 0.317924057
[1] 0.3192571 0.3200000
Q4
What is \(E(U)\) at the true value? What is \({\rm var}(U)\)? Which identity of the slides is this? Same question for mean(J_t).
2b. Two UNBIASED estimators of \(\theta\)
Q5
Which of the two unbiased estimators has smaller variance? Does the MLE reach the Cramér-Rao bound? Does the other estimator violate it?
2c. Estimate the RATE \(\lambda = 1/\theta\)
[1] 0.2288856
[1] 0.2002749
Q6
Is \(1/\bar y\) unbiased for \(\lambda\)? Why can the MLE of a function (plug-in rule) be biased even if the MLE of \(\theta\) is not?
Q7
What changes when \(n\) grows? Which property of the MLE is this?
3a. Back to the observed data: \(n = 8\), \(\hat \theta = \bar y\)
exp()q95 <- qchisq(0.95, 1)
W <- function(theta) 2 * (ll_exp(th_hat, n, S) - ll_exp(theta, n, S)) # LRT statistic
ci_wald <- th_hat + c(-1, 1) * 1.96 * th_hat / sqrt(n)
ci_wlog <- TODO # Wald on log(theta), then exp(): th_hat * exp(c(-1, 1) * 1.96 / sqrt(n))
ci_lrt <- c(uniroot(function(t) W(t) - q95, c(0.5, th_hat))$root,
uniroot(function(t) W(t) - q95, c(th_hat, 100))$root)
ci_exact <- 2 * S / qchisq(c(0.975, 0.025), df = 2 * n) # exact result
rbind(wald = ci_wald, wald_log = ci_wlog, lrt = ci_lrt, exact = ci_exact)q95 <- qchisq(0.95, 1)
W <- function(theta) 2 * (ll_exp(th_hat, n, S) - ll_exp(theta, n, S)) # LRT statistic
ci_wald <- th_hat + c(-1, 1) * 1.96 * th_hat / sqrt(n)
ci_wlog <- th_hat * exp(c(-1, 1) * 1.96 / sqrt(n)) # Wald on log(theta), then exp()
ci_lrt <- c(uniroot(function(t) W(t) - q95, c(0.5, th_hat))$root,
uniroot(function(t) W(t) - q95, c(th_hat, 100))$root)
ci_exact <- 2 * S / qchisq(c(0.975, 0.025), df = 2 * n) # exact result
rbind(wald = ci_wald, wald_log = ci_wlog, lrt = ci_lrt, exact = ci_exact) [,1] [,2]
wald 1.727074 9.522926
wald_log 2.813013 11.247947
lrt 3.021877 12.308969
exact 3.120087 13.029006
Q8
Which interval is symmetric? Which are not? Does it match P1-P2?
3b. \(H_0: \theta = 10\) (minutes) vs \(H_1: \theta \neq 10\)
theta0 <- 10
W_lrt <- W(theta0)
W_wald <- n * (th_hat - theta0)^2 / th_hat^2 # (th_hat - theta0)^2 * J(th_hat)
W_score <- U(theta0, n, S)^2 / (n / theta0^2) # U(theta0)^2 / I(theta0), with I = n / theta^2
stat <- c(LRT = W_lrt, Wald = W_wald, Score = W_score)
rbind(stat = stat, p_value = pchisq(stat, df = 1, lower.tail = FALSE)) LRT Wald Score
stat 2.2058263 4.83950617 1.5312500
p_value 0.1374902 0.02781486 0.2159249
Q9
Do the three tests lead to the same decision at level 5%? Which interval agrees with the Wald test, which with the LRT? (Is \(\theta_0 = 10\) inside each interval?)
3c. \(n = 8\), true \(\theta = 5\), \(10^5\) samples
set.seed(1)
Rr <- 1e5
Sx <- rgamma(Rr, shape = n, scale = theta_t) # sum of n exponentials
hx <- Sx / n # MLEs
cov_wald <- abs(hx - theta_t) <= 1.96 * hx / sqrt(n)
cov_wlog <- TODO # abs(log(hx) - log(theta_t)) <= 1.96 / sqrt(n)
cov_lrt <- 2 * n * (log(theta_t / hx) + hx / theta_t - 1) <= q95 # LRT statistic at theta_t <= q95
cov_exact <- (2 * Sx / theta_t >= qchisq(0.025, 2 * n)) & (2 * Sx / theta_t <= qchisq(0.975, 2 * n))
c(wald = mean(cov_wald), wald_log = mean(cov_wlog), lrt = mean(cov_lrt), exact = mean(cov_exact))set.seed(1)
Rr <- 1e5
Sx <- rgamma(Rr, shape = n, scale = theta_t) # sum of n exponentials
hx <- Sx / n # MLEs
cov_wald <- abs(hx - theta_t) <= 1.96 * hx / sqrt(n)
cov_wlog <- abs(log(hx) - log(theta_t)) <= 1.96 / sqrt(n)
cov_lrt <- 2 * n * (log(theta_t / hx) + hx / theta_t - 1) <= q95 # LRT statistic at theta_t <= q95
cov_exact <- (2 * Sx / theta_t >= qchisq(0.025, 2 * n)) & (2 * Sx / theta_t <= qchisq(0.975, 2 * n))
c(wald = mean(cov_wald), wald_log = mean(cov_wlog), lrt = mean(cov_lrt), exact = mean(cov_exact)) wald wald_log lrt exact
0.89481 0.93915 0.94768 0.94985
Q10
Which interval is closest to 95%? Why does the Wald interval undercover? Repeat with \(n = 30\) and \(n = 100\): what happens?
Q11
The LRT interval for the rate \(\lambda = 1/\theta\) is just \(1/\)(its interval for \(\theta\)); this is NOT true for the Wald interval. What property of the LRT is this? Why do the LRT and Wald-on-log nearly coincide here?
Discussion (reporter of each team)