This report was compiled from my own Jupyter notebook
(HW5.ipynb, included in this folder) with a custom Claude
Code script built by Dr. Teresa Vasquez. The math, code, and answers are
my worked solutions; the script converts the notebook into this R
Markdown file and knits it. Every number below is recomputed by R when
the file is knit.
Suppose you have 1,000 measurements and want a formula that describes where they came from. That formula is a probability distribution, and it has dials, called parameters, that need to be set. This tutorial walks through two common ways to set them, the method of moments (MM) and maximum likelihood estimation (MLE), using the heights of 1,000 adult women from the National Health and Nutrition Examination Survey (NHANES) 2009 to 2010. We try three candidate distributions (Normal, Gamma, and Exponential), check each fit with plots, estimate the median, and measure how much that median could vary from sample to sample.
| Term | What it means here | Textbook (Matloff) |
|---|---|---|
| Parameter | A dial that sets the shape of a distribution, like the center or the spread | Section 5.2, page 86 |
| Probability density function (PDF) | The smooth curve showing where values are likely to fall | Section 6.5, page 119 |
| Histogram | Bars showing how many heights fall in each range | Section 8.2, page 172 |
| Cumulative distribution function (CDF) | For any height, the fraction of women at or below it | Section 6.4.1, page 115 |
| Empirical cumulative distribution function (ECDF) | The same idea, counted straight from the data | Section 8.6, page 187 |
| Normal distribution | The bell curve, set by its center and spread | Section 6.7.2, page 127 |
| Exponential distribution | A curve that starts high at 0 and falls, built for waiting times | Section 6.7.3, page 128 |
| Gamma distribution | A curve for positive values that can lean to one side | Section 6.7.4, page 131 |
| Method of moments (MM) | Set the model’s averages equal to the data’s averages and solve | Section 8.4.1, page 181 |
| Likelihood | A score for how probable a choice of dials makes the data we saw | Section 8.4.3, page 183 |
| Maximum likelihood estimation (MLE) | Pick the dials with the highest likelihood score | Section 8.4.3, page 183 |
| Solving numerically | Letting the computer find an answer by trial and improvement when no formula exists | Section 8.4.3, page 183 |
| Unbiased | Right on average; why the variance divides by n − 1 | Section 7.6.1, page 159 |
| Kolmogorov-Smirnov (KS) distance | The biggest vertical gap between the model’s cumulative curve and the data’s | Section 8.6, page 187 |
| Median | The height that splits the women in half | |
| Sampling distribution | How an estimate would vary if we drew a new sample | Section 7.2, page 150 |
| Standard error | The typical size of that variation | Section 7.7, page 161 |
| Simulation | Using the computer to generate many fake samples | Chapter 2, page 35 |
| Quantile-quantile (QQ) plot | Sorted data plotted against where the model says each value should fall; points on the diagonal mean a match | Named in the assignment |
The three distributions and how R names their dials:
| Family | Parameters | Support | Mean | Variance | R functions |
|---|---|---|---|---|---|
| Normal | \(\mu, \sigma\) | all real numbers | \(\mu\) | \(\sigma^2\) | dnorm pnorm qnorm rnorm |
| Gamma | shape \(\alpha\), rate \(\beta\) | \(x > 0\) | \(\alpha/\beta\) | \(\alpha/\beta^2\) | dgamma pgamma qgamma rgamma |
| Exponential | rate \(\lambda\) | \(x > 0\) | \(1/\lambda\) | \(1/\lambda^2\) | dexp pexp qexp rexp |
# Setup: seed, packages, plot size, and the black-background plot style
set.seed(6110)
suppressPackageStartupMessages(library(tidyverse))
options(repr.plot.width = 15, repr.plot.height = 9)
dark <- function() par(bg = "black", col.axis = "white", col.lab = "white", col.main = "white", fg = "white")
ink <- "white" # color for the empirical cumulative distribution function steps
Before fitting anything, compute a few summary numbers. Every estimate later in this tutorial is built from them.
\(x\) = the height in centimeters of each of 1,000 adult women.
Step 1. Load the data
d1.csv was written from the homework’s exact code (shown
in the code cell). length(x) \(=
1000\) and sum(is.na(x)) \(= 0\), so there are 1,000 heights and no
missing values. Units are centimeters.
# d1.csv was created once with the homework's code:
# Hmisc::getHdata(nhgh)
# d1 <- nhgh %>% filter(sex == "female") %>% filter(age >= 18) %>%
# select(ht) %>% filter(1:n() <= 1000)
# write.csv(d1, "d1.csv", row.names = FALSE)
if (file.exists("d1.csv")) {
d1 <- read.csv("d1.csv")
} else {
Hmisc::getHdata(nhgh)
d1 <- nhgh %>% filter(sex == "female") %>% filter(age >= 18) %>%
select(ht) %>% filter(1:n() <= 1000)
}
x <- d1$ht
n <- length(x)
c(n = n, missing = sum(is.na(x)))
## n missing
## 1000 0
Step 2. Find the average height
\[\bar{x} = \frac{1}{n}\sum_{i=1}^{n} x_i = \frac{160741.9}{1000} = 160.7419 \text{ cm}\]
xbar <- mean(x)
c(sum = sum(x), xbar = xbar)
## sum xbar
## 160741.9000 160.7419
Step 3. Measure the spread two ways
Divide by \(n\):
\[\hat\sigma^2_{n} = \frac{1}{n}\sum_{i=1}^{n}(x_i - \bar{x})^2 = \frac{53531.1744}{1000} = 53.5312 \text{ cm}^2, \qquad \sqrt{53.5312} = 7.3165 \text{ cm}\]
Divide by \(n - 1\) (what
var() does):
\[s^2 = \frac{1}{n-1}\sum_{i=1}^{n}(x_i - \bar{x})^2 = \frac{53531.1744}{999} = 53.5848 \text{ cm}^2, \qquad s = \sqrt{53.5848} = 7.3202 \text{ cm}\]
The two differ by the factor \(1000/999 = 1.001\), about 0.1 percent.
Choice: divide by \(n -
1\) (var(x) \(=
53.5848\)) for the method of moments (MM).
This is the standard sample variance, the one R’s var()
computes. The \(n - 1\) version is
unbiased for \(\sigma^2\).
The \(1/n\) version \(53.5312\) is not used for the method of moments (MM); it shows up on its own as the Normal maximum likelihood estimation (MLE) in Part 1, which is biased by the factor \((n-1)/n\).
ss <- sum((x - xbar)^2)
s2 <- mean((x - xbar)^2) # divide by n: what the Normal maximum likelihood estimation (MLE) produces
v <- var(x) # divide by n - 1: used for method of moments (MM), the standard sample variance
c(sum_sq = ss, s2_n = s2, var_n_minus_1 = v, s_n = sqrt(s2), sd_n_minus_1 = sqrt(v),
ratio = v / s2)
## sum_sq s2_n var_n_minus_1 s_n sd_n_minus_1
## 53531.174390 53.531174 53.584759 7.316500 7.320161
## ratio
## 1.001001
Step 4. Average the log heights
\[\overline{\log x} = \frac{1}{n}\sum_{i=1}^{n}\log x_i = 5.078763\]
For comparison, \(\log \bar{x} = \log(160.7419) = 5.079800\). The gap \(\log\bar{x} - \overline{\log x} = 0.001037\) is tiny because the heights are tightly clustered relative to their size. This gap drives the Gamma shape estimate in Part 3.
mlog <- mean(log(x))
c(mean_log_x = mlog, log_xbar = log(xbar), gap = log(xbar) - mlog)
## mean_log_x log_xbar gap
## 5.078763038 5.079799973 0.001036935
Step 5. Check the shape
\[\operatorname{median}(x) = 160.8, \qquad \min = 139.4, \qquad \max = 190.8 \text{ cm}\]
Mean minus median \(= 160.7419 - 160.8 = -0.0581\) cm, a tiny gap compared with \(s = 7.3202\) cm. The distance from the mean to the minimum is \(160.7419 - 139.4 = 21.34\) cm and to the maximum is \(190.8 - 160.7419 = 30.06\) cm, so the upper tail reaches a little farther. The sample skewness \(\frac{1}{n}\sum (x_i - \bar{x})^3 / \hat\sigma_n^3 = 0.0757\) is close to 0. Conclusion: the heights are close to symmetric, with at most a very slight right lean.
c(median = median(x), min = min(x), max = max(x),
mean_minus_median = xbar - median(x),
skewness = mean((x - xbar)^3) / s2^1.5)
## median min max mean_minus_median
## 160.80000000 139.40000000 190.80000000 -0.05810000
## skewness
## 0.07566446
Prediction
Prediction: the Exponential will fit worst by far. Its density is highest at 0 cm and decreases from there, and it has one parameter that forces the standard deviation to equal the mean (about 161 cm), while the data are a symmetric hump near 161 cm with standard deviation about 7.3 cm. The Normal should fit well because the data look symmetric. The Gamma should look almost identical to the Normal, since a Gamma with a large shape is nearly bell shaped.
The Normal distribution is the classic bell curve. It has two dials: μ, the center, and σ, the spread. We set them both ways and compare.
\(\mu\) is the typical woman’s height, the center of the bell. \(\sigma\) is how far a typical woman sits from that center.
Step 1. Method of moments (MM): match the averages
Model moments: \(E[X] = \mu\) and \(\operatorname{Var}(X) = \sigma^2\).
Moment equations:
\[\mu = \bar{x}, \qquad \sigma^2 = s^2 = \frac{1}{n-1}\sum_{i=1}^n (x_i - \bar{x})^2\]
Solve:
\[\hat{\mu}_{\text{MM}} = \bar{x} = 160.7419 \text{ cm}\]
\[\hat{\sigma}_{\text{MM}} = \sqrt{s^2} = \sqrt{\frac{53531.1744}{999}} = \sqrt{53.5848} = 7.3202 \text{ cm}\]
(Subscript on the estimate: method of moments (MM).)
mu_mm <- xbar
sigma_mm <- sqrt(v)
c(mu_mm = mu_mm, sigma_mm = sigma_mm)
## mu_mm sigma_mm
## 160.741900 7.320161
Step 2. Maximum likelihood estimation (MLE): write the log-likelihood
The likelihood scores a choice of dials by how probable it makes the data we actually saw. Taking the log turns a product of 1,000 tiny numbers into a sum, which is easier to work with and peaks at the same place.
One point:
\[\log f(x_i; \mu, \sigma) = \log\left(\frac{1}{\sigma\sqrt{2\pi}}\right) - \frac{(x_i - \mu)^2}{2\sigma^2} = -\log\sigma - \tfrac{1}{2}\log(2\pi) - \frac{(x_i - \mu)^2}{2\sigma^2}\]
Sum over \(n\) points:
\[\ell(\mu, \sigma) = \sum_{i=1}^{n}\log f(x_i; \mu, \sigma) = -n\log\sigma - \frac{n}{2}\log(2\pi) - \frac{1}{2\sigma^2}\sum_{i=1}^{n}(x_i - \mu)^2\]
loglik_norm <- function(mu, sigma) -n * log(sigma) - n / 2 * log(2 * pi) - sum((x - mu)^2) / (2 * sigma^2)
c(formula = loglik_norm(160, 7), dnorm_sum = sum(dnorm(x, 160, 7, log = TRUE)))
## formula dnorm_sum
## -3416.702 -3416.702
Step 3. Solve for the center
Only the last term of \(\ell\) contains \(\mu\). By the chain rule, \(\frac{\partial}{\partial\mu}(x_i - \mu)^2 = -2(x_i - \mu)\):
\[\frac{\partial \ell}{\partial \mu} = -\frac{1}{2\sigma^2}\sum_{i=1}^{n} -2(x_i - \mu) = \frac{1}{\sigma^2}\sum_{i=1}^{n}(x_i - \mu)\]
Set to zero (\(\sigma^2 > 0\) so it can be multiplied away):
\[\sum_{i=1}^{n}(x_i - \mu) = 0 \;\Longrightarrow\; \sum_{i=1}^{n} x_i - n\mu = 0 \;\Longrightarrow\; \hat{\mu}_{\text{MLE}} = \frac{1}{n}\sum_{i=1}^{n} x_i = \bar{x}\]
Second derivative: \(\frac{\partial^2 \ell}{\partial \mu^2} = -\frac{n}{\sigma^2} < 0\), so this is a maximum.
\[\hat{\mu}_{\text{MLE}} = 160.7419 \text{ cm}\]
(Subscript on the estimate: maximum likelihood estimation (MLE).)
Step 4. Solve for the spread
\[\frac{\partial \ell}{\partial \sigma} = -\frac{n}{\sigma} - \frac{1}{2}\sum_{i=1}^{n}(x_i - \mu)^2 \cdot \frac{d}{d\sigma}\sigma^{-2} = -\frac{n}{\sigma} + \frac{1}{\sigma^3}\sum_{i=1}^{n}(x_i - \mu)^2\]
Set to zero and multiply both sides by \(\sigma^3\):
\[-n\sigma^2 + \sum_{i=1}^{n}(x_i - \mu)^2 = 0 \;\Longrightarrow\; \sigma^2 = \frac{1}{n}\sum_{i=1}^{n}(x_i - \mu)^2\]
Plug in \(\hat{\mu} = \bar{x}\):
\[\hat{\sigma}^2_{\text{MLE}} = \frac{1}{n}\sum_{i=1}^{n}(x_i - \bar{x})^2 = \frac{53531.1744}{1000} = 53.5312\]
\[\hat{\sigma}_{\text{MLE}} = \sqrt{53.5312} = 7.3165 \text{ cm}\]
Second derivative check at the solution: \(\frac{\partial^2 \ell}{\partial \sigma^2} = \frac{n}{\sigma^2} - \frac{3}{\sigma^4}\sum(x_i - \bar{x})^2 = \frac{n}{\hat\sigma^2} - \frac{3n\hat\sigma^2}{\hat\sigma^4} = -\frac{2n}{\hat{\sigma}^2} < 0\), a maximum.
The maximized log-likelihood is \(\ell(\hat\mu, \hat\sigma) = -3409.0706\).
mu_mle <- xbar
sigma_mle <- sqrt(mean((x - mu_mle)^2))
num <- optim(c(150, 5), function(p) -loglik_norm(p[1], p[2]))
c(mu_mle = mu_mle, sigma_mle = sigma_mle, optim_mu = num$par[1], optim_sigma = num$par[2],
loglik = loglik_norm(mu_mle, sigma_mle))
## mu_mle sigma_mle optim_mu optim_sigma loglik
## 160.741900 7.316500 160.739829 7.316427 -3409.070625
How the two methods compare
The centers are identical: \(\hat\mu = 160.7419\) from both. The spreads differ slightly: \(\hat\sigma_{\text{MM}} = 7.3202\) vs \(\hat\sigma_{\text{MLE}} = 7.3165\), a difference of \(0.0037\) cm (0.05 percent). The cause is only the divisor. The maximum likelihood estimation (MLE) calculus produces \(1/n\); the method of moments (MM) here uses \(n - 1\). Had the method of moments (MM) used \(1/n\), the two would match exactly. With \(n = 1000\) the difference is far too small to see in any plot.
The Gamma forbids negative heights and allows a lean to one side. Shape \(\alpha\) controls how bell-like it is; rate \(\beta\) controls the scale. Mean \(= \alpha/\beta\), variance \(= \alpha/\beta^2\).
Step 1. Write the moment equations
\[\text{(1)}\quad \frac{\alpha}{\beta} = \bar{x} = 160.7419\]
\[\text{(2)}\quad \frac{\alpha}{\beta^2} = s^2 = 53.5848 \quad (\text{divide by } n - 1)\]
Step 2. Solve for the rate
\[\frac{(1)}{(2)}: \quad \frac{\alpha/\beta}{\alpha/\beta^2} = \frac{\alpha}{\beta}\cdot\frac{\beta^2}{\alpha} = \beta = \frac{\bar{x}}{s^2}\]
\(\alpha\) cancels, and one factor of \(\beta\) cancels, leaving \(\beta\) alone.
\[\hat{\beta}_{\text{MM}} = \frac{\bar{x}}{s^2}\]
Step 3. Solve for the shape
From (1), \(\alpha = \beta\,\bar{x}\). Substitute \(\hat\beta = \bar{x}/s^2\):
\[\hat{\alpha}_{\text{MM}} = \frac{\bar{x}}{s^2}\cdot\bar{x} = \frac{\bar{x}^2}{s^2}, \qquad \hat{\beta}_{\text{MM}} = \frac{\bar{x}}{s^2}\]
Step 4. Plug in the numbers
\[\hat{\beta}_{\text{MM}} = \frac{160.7419}{53.5848} = 2.9998\]
\[\hat{\alpha}_{\text{MM}} = \frac{160.7419^2}{53.5848} = \frac{25837.96}{53.5848} = 482.19\]
Check: \(\hat\alpha/\hat\beta = 482.19 / 2.9998 = 160.7419\) (matches \(\bar{x}\)) and \(\hat\alpha/\hat\beta^2 = 53.5848\) (matches \(s^2\)).
(With the \(1/n\) variance instead, you would get \(\hat\alpha = 482.67\) and \(\hat\beta = 3.0028\).)
b_mm <- xbar / v
a_mm <- xbar^2 / v
c(a_mm = a_mm, b_mm = b_mm, model_mean = a_mm / b_mm, model_var = a_mm / b_mm^2)
## a_mm b_mm model_mean model_var
## 482.188571 2.999769 160.741900 53.584759
What a large shape means
A Gamma with shape \(\alpha\) has skewness \(2/\sqrt{\alpha}\). With \(\hat\alpha = 482.19\) that is \(2/\sqrt{482.19} = 0.0911\), almost 0, so this Gamma is a nearly symmetric bell. Its plots should be almost indistinguishable from the Normal’s, with the Gamma curve very slightly shifted so its right tail is a touch longer.
Same Gamma family, different tuning rule: which \(\alpha\) and \(\beta\) make these exact 1,000 women the most plausible?
Step 1. Write the log-likelihood
Gamma density with shape \(\alpha\) and rate \(\beta\): \(f(x) = \dfrac{\beta^\alpha}{\Gamma(\alpha)} x^{\alpha - 1} e^{-\beta x}\). Taking the log of one point:
\[\log f(x_i; \alpha, \beta) = \alpha\log\beta - \log\Gamma(\alpha) + (\alpha - 1)\log x_i - \beta x_i\]
Sum over \(n\) points, using \(\sum x_i = n\bar{x}\) and \(\sum \log x_i = n\,\overline{\log x}\):
\[\ell(\alpha, \beta) = n\alpha\log\beta - n\log\Gamma(\alpha) + (\alpha - 1)\, n\,\overline{\log x} - \beta\, n\bar{x}\]
With numbers:
\[\ell(\alpha, \beta) = 1000\left[\alpha\log\beta - \log\Gamma(\alpha) + (\alpha - 1)(5.078763) - 160.7419\,\beta\right]\]
loglik_gamma <- function(a, b) n * (a * log(b) - lgamma(a) + (a - 1) * mlog - b * xbar)
c(formula = loglik_gamma(a_mm, b_mm), dgamma_sum = sum(dgamma(x, shape = a_mm, rate = b_mm, log = TRUE)))
## formula dgamma_sum
## -3408.705 -3408.705
Step 2. Solve for the rate
\[\frac{\partial \ell}{\partial \beta} = \frac{n\alpha}{\beta} - n\bar{x} = 0 \;\Longrightarrow\; \frac{\alpha}{\beta} = \bar{x} \;\Longrightarrow\; \hat{\beta}_{\text{MLE}} = \frac{\hat{\alpha}_{\text{MLE}}}{\bar{x}}\]
So the maximum likelihood estimation (MLE) fit always matches the sample mean exactly: \(\hat\alpha/\hat\beta = \bar{x}\).
Step 3. The shape equation has no formula
With \(\psi(\alpha) = \frac{d}{d\alpha}\log\Gamma(\alpha)\):
\[\frac{\partial \ell}{\partial \alpha} = n\log\beta - n\,\psi(\alpha) + n\,\overline{\log x} = 0\]
Substitute \(\beta = \alpha/\bar{x}\) from Step 2:
\[\log\alpha - \log\bar{x} - \psi(\alpha) + \overline{\log x} = 0 \;\Longrightarrow\; \log\alpha - \psi(\alpha) = \log\bar{x} - \overline{\log x}\]
With numbers, the right side is \(5.079800 - 5.078763 = 0.001037\):
\[\log\alpha - \psi(\alpha) = 0.001037\]
When we take the slope with respect to α, α ends up both inside a log
and inside another function built from the Gamma function. There is no
way to rearrange the equation to get α by itself, so the computer has to
solve it numerically (textbook Section 8.4.3). R calls that function
digamma(). All you need to know is that it has no simple
formula. One clue helps: the right side of the equation is the gap from
Part 0, 0.001037. A gap that small means α must be large, around
482.
gap <- log(xbar) - mlog
c(rhs = gap, lhs_at_a_mm = log(a_mm) - digamma(a_mm), rough_alpha = 1 / (2 * gap))
## rhs lhs_at_a_mm rough_alpha
## 1.036935e-03 1.037297e-03 4.821903e+02
Step 4. Let the computer search
Negative log-likelihood on the log scale, \(p = (\log\alpha, \log\beta)\):
\[\text{nll}(p) = -\sum_{i=1}^{n}\log f\!\left(x_i;\ e^{p_1}, e^{p_2}\right)\]
Start: \(p_0 = (\log 482.19, \log 2.9998)\).
R’s optim() finds the best α and β by trial and
improvement. It starts at the method of moments (MM) values, tries
nearby values, keeps whichever makes the data more likely, and stops
when the improvements get very small. With R’s default stopping setting
it quit too early, at α = 482.47. Near the top, the likelihood barely
changes along the line β = α/x̄, so the improvements looked small before
it had reached the peak. Telling it to keep going longer
(reltol = 1e-12 in the code) gave α = 482.36 and β =
3.0008. The search works on log α and log β so it can never try a
negative value. Solving the Step 3 equation a second way, with
uniroot(), gives the same α = 482.36.
\[\hat{\alpha}_{\text{MLE}} = 482.36, \qquad \hat{\beta}_{\text{MLE}} = 3.0008, \qquad \texttt{fit\$convergence} = 0\]
The maximized log-likelihood is \(-3408.7050\), slightly higher than the Normal’s \(-3409.0706\).
fit_gamma_mle <- function(v, start, reltol = 1e-12) {
nll <- function(p) -sum(dgamma(v, shape = exp(p[1]), rate = exp(p[2]), log = TRUE))
optim(log(start), nll, control = list(reltol = reltol))
}
fit_default <- fit_gamma_mle(x, c(a_mm, b_mm), reltol = 1e-8)
fit <- fit_gamma_mle(x, c(a_mm, b_mm))
a_mle <- exp(fit$par[1]); b_mle <- exp(fit$par[2])
a_exact <- uniroot(function(a) log(a) - digamma(a) - gap, c(1, 1e4), tol = 1e-12)$root
c(default_a = exp(fit_default$par[1]), default_b = exp(fit_default$par[2]),
a_mle = a_mle, b_mle = b_mle, convergence = fit$convergence,
a_uniroot = a_exact, loglik = -fit$value)
## default_a default_b a_mle b_mle convergence a_uniroot
## 482.465629 3.001518 482.356598 3.000814 0.000000 482.356894
## loglik
## -3408.704954
Step 5. Confirm the answer
\[\frac{\hat\alpha}{\bar{x}} = \frac{482.36}{160.7419} = 3.000814 \qquad \text{vs} \qquad \hat\beta = 3.000814\]
They agree to 7 significant digits, so the optimizer did land on the ridge \(\beta = \alpha/\bar{x}\) that Step 2 requires.
c(b_mle = b_mle, a_mle_over_xbar = a_mle / xbar, model_mean = a_mle / b_mle)
## b_mle a_mle_over_xbar model_mean
## 3.000814 3.000814 160.741896
How the two Gamma fits compare
| shape \(\hat\alpha\) | rate \(\hat\beta\) | mean \(\hat\alpha/\hat\beta\) | |
|---|---|---|---|
| method of moments (MM) | 482.19 | 2.9998 | 160.7419 |
| maximum likelihood estimation (MLE) | 482.36 | 3.0008 | 160.7419 |
| change | 0.17 (0.035 percent) | 0.0010 (0.035 percent) | 0.0000 |
The shape moved more in absolute terms (up 0.17 vs up 0.0010); in relative terms both rose by the same 0.035 percent, because the rate is tied to the shape through \(\beta = \alpha/\bar{x}\). The mean does not change: both methods force \(\hat\alpha/\hat\beta = \bar{x}\). Only the implied variance \(\hat\alpha/\hat\beta^2 = \bar{x}/\hat\beta\) changes, from 53.5848 to 53.5661. The maximum likelihood estimation (MLE) variance sits between the \(n - 1\) variance 53.5848 and the \(1/n\) variance 53.5312.
The Exponential is a one-dial model built for waiting times. Using it for height is a stress test: the homework includes it on purpose so you can see what a wrong family does.
Step 1. Method of moments (MM)
Model mean \(= 1/\lambda\). Set equal to the sample mean:
\[\frac{1}{\lambda} = \bar{x} \;\Longrightarrow\; \hat\lambda_{\text{MM}} = \frac{1}{\bar{x}} = \frac{1}{160.7419} = 0.0062212 \text{ per cm}\]
lam_mm <- 1 / xbar
lam_mm
## [1] 0.006221153
Step 2. Maximum likelihood estimation (MLE)
Density \(f(x; \lambda) = \lambda e^{-\lambda x}\). Log of one term: \(\log\lambda - \lambda x_i\). Sum over \(n\):
\[\ell(\lambda) = n\log\lambda - \lambda\sum_{i=1}^{n} x_i\]
\[\frac{d\ell}{d\lambda} = \frac{n}{\lambda} - \sum_{i=1}^{n} x_i = 0 \;\Longrightarrow\; \hat\lambda = \frac{n}{\sum x_i} = \frac{1}{\bar{x}}\]
\[\frac{d^2\ell}{d\lambda^2} = -\frac{n}{\lambda^2} < 0 \;\text{(maximum)}\]
\[\hat\lambda_{\text{MLE}} = \frac{1000}{160741.9} = \frac{1}{160.7419} = 0.0062212 \text{ per cm}\]
Same as the method of moments (MM). Maximized log-likelihood: \(\ell(\hat\lambda) = -6079.8000\), far below the Normal’s \(-3409.0706\).
lam_mle <- n / sum(x)
num <- optimize(function(l) n * log(l) - l * sum(x), c(1e-5, 1), maximum = TRUE, tol = 1e-12)
c(lam_mle = lam_mle, optimize_check = num$maximum, loglik = n * log(lam_mle) - lam_mle * sum(x))
## lam_mle optimize_check loglik
## 6.221153e-03 6.221153e-03 -6.079800e+03
Step 3. Compare the fit to the data
| value (cm) | |
|---|---|
| fitted mean \(1/\hat\lambda\) | 160.7419 |
| fitted peak (mode) | 0 |
| sample mean \(\bar{x}\) | 160.7419 |
| fitted standard deviation \(1/\hat\lambda\) | 160.7419 |
| sample standard deviation \(s\) | 7.3202 |
The Exponential matches the mean by construction, but it puts its peak at 0 cm and its standard deviation equal to its mean, about 22 times the real spread.
What to expect from the plot
The histogram is a tall narrow hump from about 139 to 191 cm reaching a density near 0.055. The Exponential curve starts at height \(\hat\lambda = 0.0062212\) at 0 cm and decays slowly, reaching about \(0.00229\) at 160.7 cm. So the curve is a nearly flat, low line that is highest where there are no women and far below the bars where the women are.
A fitted distribution is only useful if it looks like the data. We check all six fits three ways, because each plot catches a different kind of mismatch.
Six fits: Normal, Gamma, Exponential, each by method of moments (MM) and by maximum likelihood estimation (MLE).
Step 1. Density over histogram
Six panels below, one per fit. Normal and Gamma panels use 135 to 195
cm; Exponential panels use 0 to 250 cm so the curve’s peak at 0 is
visible. Histogram: 30 bins on the density scale
(freq = FALSE).
fits <- list(
list(fam = "Normal", meth = "method of moments (MM)",
d = function(v) dnorm(v, mu_mm, sigma_mm), p = function(v) pnorm(v, mu_mm, sigma_mm),
q = function(pr) qnorm(pr, mu_mm, sigma_mm), lim = c(135, 195)),
list(fam = "Normal", meth = "maximum likelihood estimation (MLE)",
d = function(v) dnorm(v, mu_mle, sigma_mle), p = function(v) pnorm(v, mu_mle, sigma_mle),
q = function(pr) qnorm(pr, mu_mle, sigma_mle), lim = c(135, 195)),
list(fam = "Gamma", meth = "method of moments (MM)",
d = function(v) dgamma(v, shape = a_mm, rate = b_mm), p = function(v) pgamma(v, shape = a_mm, rate = b_mm),
q = function(pr) qgamma(pr, shape = a_mm, rate = b_mm), lim = c(135, 195)),
list(fam = "Gamma", meth = "maximum likelihood estimation (MLE)",
d = function(v) dgamma(v, shape = a_mle, rate = b_mle), p = function(v) pgamma(v, shape = a_mle, rate = b_mle),
q = function(pr) qgamma(pr, shape = a_mle, rate = b_mle), lim = c(135, 195)),
list(fam = "Exponential", meth = "method of moments (MM)",
d = function(v) dexp(v, rate = lam_mm), p = function(v) pexp(v, rate = lam_mm),
q = function(pr) qexp(pr, rate = lam_mm), lim = c(0, 250)),
list(fam = "Exponential", meth = "maximum likelihood estimation (MLE)",
d = function(v) dexp(v, rate = lam_mle), p = function(v) pexp(v, rate = lam_mle),
q = function(pr) qexp(pr, rate = lam_mle), lim = c(0, 250)))
ttl <- function(f) paste0(f$fam, "\n", f$meth)
dark(); par(mfrow = c(2, 3))
for (f in fits) {
hist(x, freq = FALSE, breaks = 30, xlim = f$lim, ylim = c(0, 0.065), col = "gray30", border = "gray60",
main = ttl(f), xlab = "height (cm)")
curve(f$d(x), from = f$lim[1], to = f$lim[2], n = 1001, add = TRUE, col = "deepskyblue", lwd = 3)
}
Step 2. Cumulative curves
The Kolmogorov-Smirnov (KS) distance is the largest vertical gap between the fitted curve and the data’s curve. 0 means perfect agreement, and 1 is the worst possible.
dark(); par(mfrow = c(2, 3))
Fn <- ecdf(x); xs <- sort(x)
ks_gap <- function(f) max(abs(c(Fn(xs) - f$p(xs), Fn(xs) - 1 / n - f$p(xs))))
for (f in fits) {
plot(Fn, do.points = FALSE, verticals = TRUE, xlim = f$lim, col = ink, lwd = 2,
main = ttl(f), xlab = "height (cm)", ylab = "cumulative probability")
curve(f$p(x), from = f$lim[1], to = f$lim[2], n = 1001, add = TRUE, col = "deepskyblue", lwd = 3, lty = 2)
}
sapply(fits, ks_gap)
## [1] 0.01545283 0.01533868 0.01689911 0.01686009 0.58170101 0.58170101
Step 3. Quantile-quantile (QQ) plot
A quantile-quantile (QQ) plot pairs each sorted height with where the fitted distribution says that height should fall. Points on the 45 degree line mean the two agree.
dark(); par(mfrow = c(2, 3))
for (f in fits) {
model_q <- f$q(ppoints(n))
plot(model_q, sort(x), pch = 16, cex = 0.6, col = "deepskyblue", main = ttl(f),
xlab = "model quantile (cm)", ylab = "sample quantile (cm)",
xlim = range(model_q, x), ylim = range(model_q, x))
abline(0, 1, col = "orange", lwd = 2)
}
range(fits[[5]]$q(ppoints(n)))
## [1] 8.039105e-02 1.221784e+03
Step 4. All six fits at a glance
| Fit | Probability density function (PDF) over histogram | Cumulative distribution function (CDF) over empirical cumulative distribution function (ECDF) | Quantile-quantile (QQ) plot |
|---|---|---|---|
| Normal, method of moments (MM) | Center and spread match; tails follow the bars. | Hugs the steps everywhere; largest gap 0.0155. | On the line from 145 to 175 cm; tallest women above the line (upper tail slightly longer than the model). |
| Normal, maximum likelihood estimation (MLE) | Indistinguishable from the method of moments (MM) fit. | Hugs the steps; largest gap 0.0153. | Indistinguishable from the method of moments (MM) fit. |
| Gamma, method of moments (MM) | Indistinguishable from the Normal. | Hugs the steps; largest gap 0.0169. | On the line; extremes slightly closer to it than the Normal’s, a few points near 142 cm just below. |
| Gamma, maximum likelihood estimation (MLE) | Indistinguishable from the Gamma method of moments (MM) fit. | Hugs the steps; largest gap 0.0169. | Same as the Gamma method of moments (MM) fit. |
| Exponential, method of moments (MM) | Wrong shape: peak at 0 cm, curve far below the bars. | Wrong everywhere; largest gap 0.5817. | Strong curve far off the line; center, spread, and tails all wrong. |
| Exponential, maximum likelihood estimation (MLE) | Identical to the method of moments (MM) fit. | Identical; largest gap 0.5817. | Identical. |
The median is the height that splits the women in half. Each fitted distribution has its own median. Because each fit came from one sample, a different sample would give a slightly different median. Here we compute each median and measure how much it could vary.
Step 1. Median of each fitted distribution
The model median \(m\) solves \(F(m; \hat\theta) = 0.5\), which is what the q-function returns at 0.5.
qnorm(0.5, 160.7419, 7.3202) \(= 160.7419\) for the method of moments
(MM), and qnorm(0.5, 160.7419, 7.3165) gives the same
160.7419 for the maximum likelihood estimation (MLE), since \(\hat\sigma\) does not affect the
median.qgamma(0.5, shape = 482.19, rate = 2.9998) \(= 160.6308\).qgamma(0.5, shape = 482.36, rate = 3.0008) \(= 160.6308\).| Fit | Model median (cm) | median(x) (cm) |
Model minus data |
|---|---|---|---|
| Normal, method of moments (MM) | 160.7419 | 160.8 | -0.0581 |
| Normal, maximum likelihood estimation (MLE) | 160.7419 | 160.8 | -0.0581 |
| Gamma, method of moments (MM) | 160.6308 | 160.8 | -0.1692 |
| Gamma, maximum likelihood estimation (MLE) | 160.6308 | 160.8 | -0.1692 |
| Exponential, method of moments (MM) | 111.4178 | 160.8 | -49.3822 |
| Exponential, maximum likelihood estimation (MLE) | 111.4178 | 160.8 | -49.3822 |
model_medians <- c(normal_mm = qnorm(0.5, mu_mm, sigma_mm),
normal_mle = qnorm(0.5, mu_mle, sigma_mle),
gamma_mm = qgamma(0.5, shape = a_mm, rate = b_mm),
gamma_mle = qgamma(0.5, shape = a_mle, rate = b_mle),
exp_mm = qexp(0.5, rate = lam_mm),
exp_mle = qexp(0.5, rate = lam_mle))
round(cbind(model = model_medians, data = median(x), model_minus_data = model_medians - median(x)), 4)
## model data model_minus_data
## normal_mm 160.7419 160.8 -0.0581
## normal_mle 160.7419 160.8 -0.0581
## gamma_mm 160.6308 160.8 -0.1692
## gamma_mle 160.6308 160.8 -0.1692
## exp_mm 111.4178 160.8 -49.3822
## exp_mle 111.4178 160.8 -49.3822
Step 2. Which medians land near the data
Normal and Gamma medians land within 0.2 cm of median(x)
\(= 160.8\) (Normal \(-0.0581\), Gamma \(-0.1692\) and \(-0.1692\)). The Gamma median sits a hair
left of its mean because of its slight right skew. These are the fits
whose curves traced the histogram and whose quantile-quantile (QQ)
points sat on the line. The Exponential median is \(111.4178\) cm, \(49.38\) cm below the data median, matching
the quantile-quantile (QQ) plot where every model percentile was in the
wrong place.
Step 3. Simulate one fit
How much could the median change with a different sample? To find out, we simulate. We treat the fitted distribution as if it were the truth, draw a fake sample of 1,000 heights from it, refit it the same way, and record its median. We repeat that 5,000 times. The spread of those 5,000 medians is the median’s sampling distribution (textbook Section 7.2), and its standard deviation is the standard error.
Fit: Normal, method of moments (MM). \(B =
5000\), seed set once at the top (set.seed(6110)),
no other random calls before this point.
For \(b = 1, \dots, B\):
sd()).qnorm(0.5, mu_star, sigma_star), which equals \(\hat\mu^*\).Result: standard error \(= \operatorname{sd}(m^*) = 0.2334\) cm; middle 95 percent from 160.2878 to 161.2153 cm.
Sanity check: the model median of a Normal fit equals \(\bar{x}^*\), whose standard error is \(\hat\sigma/\sqrt{n} = 7.3202/\sqrt{1000} = 0.2315\) cm. The simulation gives 0.2334.
B <- 5000
refit_normal_mm <- function(s) qnorm(0.5, mean(s), sd(s)) # divide by n - 1
refit_normal_mle <- function(s) { m <- mean(s); qnorm(0.5, m, sqrt(mean((s - m)^2))) } # divide by n
boot_normal_mm <- replicate(B, refit_normal_mm(rnorm(n, mu_mm, sigma_mm)))
c(se = sd(boot_normal_mm), quantile(boot_normal_mm, c(0.025, 0.975)), theory_se = sigma_mm / sqrt(n))
## se 2.5% 97.5% theory_se
## 0.2334025 160.2877582 161.2152591 0.2314838
Step 4. Simulate all six
Each fit is refit with its own method inside the loop: Normal maximum
likelihood estimation (MLE) with the \(1/n\) standard deviation; Gamma method of
moments (MM) with \(\bar{x}^{*2}/s^{*2}\) and \(\bar{x}^*/s^{*2}\) using
var(); Gamma maximum likelihood estimation (MLE) with
optim() started at that fake sample’s method of moments
(MM) values (all \(B\) runs reported
convergence code 0: 0 failures); Exponential with \(1/\bar{x}^*\).
| Fit | Model median | Simulated standard error | 2.5th percentile | 97.5th percentile | Contains median(x) = 160.8? |
|---|---|---|---|---|---|
| Normal, method of moments (MM) | 160.7419 | 0.2334 | 160.2878 | 161.2153 | yes |
| Normal, maximum likelihood estimation (MLE) | 160.7419 | 0.2303 | 160.2941 | 161.1987 | yes |
| Gamma, method of moments (MM) | 160.6308 | 0.2338 | 160.1655 | 161.0856 | yes |
| Gamma, maximum likelihood estimation (MLE) | 160.6308 | 0.2268 | 160.1913 | 161.0746 | yes |
| Exponential, method of moments (MM) | 111.4178 | 3.5122 | 104.6399 | 118.5099 | no |
| Exponential, maximum likelihood estimation (MLE) | 111.4178 | 3.4731 | 104.7166 | 118.5363 | no |
The Normal and Gamma histograms are narrow bells centered on their model medians with standard error about 0.23 cm. The Exponential histogram is centered near 111 cm with standard error about 3.5122 cm, about 15 times wider, because the Exponential’s spread is tied to its mean.
refit_gamma_mm <- function(s) { m <- mean(s); vs <- var(s); qgamma(0.5, shape = m^2 / vs, rate = m / vs) }
nonconv <- 0
refit_gamma_mle <- function(s) {
m <- mean(s); vs <- var(s)
f <- fit_gamma_mle(s, c(m^2 / vs, m / vs)) # start at this sample's method of moments (MM) values
if (f$convergence != 0) nonconv <<- nonconv + 1
qgamma(0.5, shape = exp(f$par[1]), rate = exp(f$par[2]))
}
refit_exp <- function(s) qexp(0.5, rate = 1 / mean(s))
boot_normal_mle <- replicate(B, refit_normal_mle(rnorm(n, mu_mle, sigma_mle)))
boot_gamma_mm <- replicate(B, refit_gamma_mm(rgamma(n, shape = a_mm, rate = b_mm)))
boot_gamma_mle <- replicate(B, refit_gamma_mle(rgamma(n, shape = a_mle, rate = b_mle)))
boot_exp_mm <- replicate(B, refit_exp(rexp(n, rate = lam_mm)))
boot_exp_mle <- replicate(B, refit_exp(rexp(n, rate = lam_mle)))
boots <- list(normal_mm = boot_normal_mm, normal_mle = boot_normal_mle, gamma_mm = boot_gamma_mm,
gamma_mle = boot_gamma_mle, exp_mm = boot_exp_mm, exp_mle = boot_exp_mle)
boot_table <- t(sapply(boots, function(v) c(se = sd(v), quantile(v, c(0.025, 0.975)))))
print(round(cbind(model_median = model_medians, boot_table), 4))
## model_median se 2.5% 97.5%
## normal_mm 160.7419 0.2334 160.2878 161.2153
## normal_mle 160.7419 0.2303 160.2941 161.1987
## gamma_mm 160.6308 0.2338 160.1655 161.0856
## gamma_mle 160.6308 0.2268 160.1913 161.0746
## exp_mm 111.4178 3.5122 104.6399 118.5099
## exp_mle 111.4178 3.4731 104.7166 118.5363
cat("Gamma maximum likelihood refits that did not converge:", nonconv, "\n")
## Gamma maximum likelihood refits that did not converge: 0
dark(); par(mfrow = c(2, 3))
for (i in seq_along(boots)) {
hist(boots[[i]], breaks = 40, freq = FALSE, col = "gray30", border = "gray60",
main = ttl(fits[[i]]), xlab = "simulated model median (cm)")
abline(v = model_medians[i], col = "deepskyblue", lwd = 3)
abline(v = quantile(boots[[i]], c(0.025, 0.975)), col = "orange", lwd = 2, lty = 2)
abline(v = median(x), col = "red", lwd = 2, lty = 3)
}
Does a narrow interval mean the model is right?
No. The Exponential’s 95 percent simulated interval, 104.6399 to 118.5099 cm, is only about 13.9 cm wide, yet even its upper end sits about 42 cm below the data median 160.8 cm and does not contain it. The simulation treats the fitted model as the truth, so it only measures how much the estimate would wobble if the model were right. It says nothing about whether the family is right. Model checking (Part 5) answers that question.
Every item on the assignment’s checklist, for both methods and all three distributions, and where to find it in this tutorial.
| Item | Normal, MM | Normal, MLE | Gamma, MM | Gamma, MLE | Exponential, MM | Exponential, MLE |
|---|---|---|---|---|---|---|
| Estimates of parameters | μ = 160.7419, σ = 7.3202 | μ = 160.7419, σ = 7.3165 | α = 482.19, β = 2.9998 | α = 482.36, β = 3.0008 | λ = 0.006221 | λ = 0.006221 |
| Estimated PDF over histogram | ✓ Part 5, Step 1 | ✓ Part 5, Step 1 | ✓ Part 5, Step 1 | ✓ Part 5, Step 1 | ✓ Part 5, Step 1 | ✓ Part 5, Step 1 |
| Estimated CDF over ECDF | ✓ Part 5, Step 2 | ✓ Part 5, Step 2 | ✓ Part 5, Step 2 | ✓ Part 5, Step 2 | ✓ Part 5, Step 2 | ✓ Part 5, Step 2 |
| QQ plot (sample vs. estimated) | ✓ Part 5, Step 3 | ✓ Part 5, Step 3 | ✓ Part 5, Step 3 | ✓ Part 5, Step 3 | ✓ Part 5, Step 3 | ✓ Part 5, Step 3 |
| Estimated median (simulated standard error) | 160.7419 (0.2334) | 160.7419 (0.2303) | 160.6308 (0.2338) | 160.6308 (0.2268) | 111.4178 (3.5122) | 111.4178 (3.4731) |
MM = method of moments; MLE = maximum likelihood estimation. The real median of the 1,000 heights is 160.8 cm.
Step back and compare. Which mattered more: the method or the choice of distribution?
Step 1. Method versus method
Step 2. Distribution versus distribution
median(x) (-0.0581 vs -0.1692). With a Gamma shape near 480
the two curves are visually identical. For a newcomer, the Normal is the
simpler choice, because its two parameters are the mean and the standard
deviation directly.Step 3. Which choice mattered more
The family. Changing the method moved the Gamma model median by 0.00003 cm. Changing the family from Normal to Exponential moved the model median by 49.32 cm, from 160.7419 to 111.4178. The family change was over a million times larger.
Step 4. Assumptions
var() \(= 53.5848\)). The \(1/n\) version (\(53.5312\)) appears only as the Normal
maximum likelihood estimation (MLE).set.seed(6110) set once at the top, run in the order Normal
method of moments (MM), Normal maximum likelihood estimation (MLE),
Gamma method of moments (MM), Gamma maximum likelihood estimation (MLE),
Exponential method of moments (MM), Exponential maximum likelihood
estimation (MLE).optim() searching over log α and log β, starting at the
method of moments (MM) values, with a tighter stopping setting than R’s
default because the default quit early. Confirmed by solving the
equation a second way with uniroot().shape = and rate =.Step 5. Take-home messages
var() divides by n − 1,
and optim() can stop searching before it reaches the peak.
Name every argument, state your divisor, and confirm the computer’s
answer a second way.