mle#
Series: lecture-python.myst
File:
lectures/mle.mdAudit date: 2026-08-26
Corpus snapshot:
e25fdf2345Categories audited: writing, math, code, figures, references, links, admonitions (JAX out of scope)
Overall score: 7.2 / 10
Priority: HIGH
Score breakdown#
Category |
Score |
One-line note |
|---|---|---|
Writing |
4.5/10 |
|
Math |
3/10 |
|
Code |
7.5/10 |
|
JAX |
out of scope |
JAX rules target |
Figures |
5.5/10 |
|
References |
10/10 |
no mechanical violations detected. |
Links |
10/10 |
no mechanical violations detected. |
Admonitions |
10/10 |
no mechanical violations detected. |
Issues#
Critical#
None found.
High severity#
[qe-code-001] (reviewer) — Follow PEP8 unless closer to mathematical notation. Count: 7. Lines: 66, 433, 500, 550, 611, 631, 785. Example: the name
logLis bound to four different functions - 403 (scalar quadratic), 497 (logL(\u03b2, model)for the Poisson), 611 (scalar quadratic again) and 946 (the Probit) - andG_logL/H_logLare rebound twice, at 515-516 and 953-954.newton_raphson(536-565) then readsG_logLandH_logLout of module globals at 550 instead of taking them as arguments, so the Probit call at 1027 silently depends on 953-954 having run, and the Poisson call at 583 stops working once they have.\u03b2is likewise three different objects: a coefficient vector at 221 and 577, ajnp.linspacegrid at 416 and 627, and a float loop variable at 631, where the loop shadows the grid the previous line just plotted. Two imports are dead -gammaln(66) andAxes3D(73, the 3-D axes come fromadd_subplot(projection="3d")at 302) - andgammalnis exactly what 500 needs:jnp.log(factorial(y))overflows for the sample it is written for, whilegammaln(y + 1)is the stable form and is already imported. 498 bindsy = model.yand 500 then uses bothmodel.yandyin one expression. 404 and 612 space the exponentiation (-((\u03b2 - 10) ** 2)). 433 puts two calls on one line as a tuple,ax1.grid(), ax2.grid(). And 785-786 uses a backslash continuation inside a string literal, so the printed table title reads “Explaining the Number of Billionaires” followed by twenty-four spaces before “in 2008”.[qe-fig-001] — Do not set figure size unless necessary. Count: 7. Lines: 130, 180, 232, 301, 418, 628, 827. Example: figsize=.
[qe-fig-005] — Descriptive figure names for cross-referencing. Count: 6. Lines: 127, 175, 217, 415, 624, 800. Example: code-cell figure without mystnb figure metadata.
[qe-math-002] — Use \top for transpose notation. Count: 19. Lines: 207, 465, 871, 900, 901, 918, 919, 926, 927, 929, …. Example: apostrophe transpose
i'.[qe-math-004] — Do not use bold face for matrices or vectors. Count: 106. Lines: 195, 202, 207, 212, 215, 257, 264, 267, 276, 278, …. Example: \mathbf.
[qe-math-009] (reviewer) — Choose simplicity in mathematical notation. Count: 5. Lines: 288, 398, 424, 469, 686. Example: the likelihood is written both ways, and one of them is wrong:
\mathcal{L}(\boldsymbol{\beta})at 280, 339, 351, 594, 898, 916 and 926, but\mathcal{L(\beta)}- argument inside the calligraphic group, so the parenthesis and the \(\beta\) render calligraphic too - at 398, 424, 427, 439, 464, 465 and 643. In the same axis labels,logis typed as three italic letters rather than\log(424$log \mathcal{L(\beta)}$, 427\frac{dlog \mathcal{L(\beta)}}{d \beta}, 643), where 351, 398, 439, 594, 898 and 916 use\log. The Poisson mean is \(\mu\) in every display (115, 202, 208, 318, 363) and in the code (123, 235, 292, 499), but 288 calls it \(\lambda\) once - “If \(y_i\) follows a Poisson distribution with \(\lambda = 7\)” - immediately above a cell that passes\u03bc=7. 686-689 typesets four multi-word prose labels as italic math with manual spacers,${number\ of\ billionaires}_i$,$\log{GDP\ per\ capita}_i$,$\log{population}_i$,${years\ in\ GATT}_i$, where\text{...}is both shorter and correct. And 469 writes< tolin math mode, rendering the tolerance as the product of three variables.
Medium severity#
[qe-fig-006] — Lowercase axis labels. Count: 4. Lines: 184, 185, 829, 830. Example: axis label
Number of billionaires in 2008.[qe-fig-008] — Use lw=2 for line charts. Count: 3. Lines: 136, 239, 635. Example: plot() without lw=.
[qe-writing-001] — Use one sentence per paragraph. Count: 1. Lines: 740. Example: 2 sentences in one paragraph.
[qe-writing-002] (reviewer) — Keep writing clear, concise, and valuable. Count: 4. Lines: 282, 324, 510, 905. Example: 324-326 tells the reader something false about the central object of the lecture: “The likelihood function is the same as the joint pmf, but treats the parameter \(\boldsymbol{\beta}\) as a random variable and takes the observations \((y_i, \mathbf{x}_i)\) as given.” In maximum likelihood \(\boldsymbol{\beta}\) is the argument of the function, not a random variable - treating it as random is the Bayesian reading, which this lecture is not doing. 905 and 911 make a second terminology error twice over: “the derivative of a cumulative probability distribution is its marginal distribution” and “\(\phi\) is the marginal normal distribution” - \(\phi\) is the density, and “marginal” means something else. 282 writes “Assume we have some data \(y_i = \{y_1, y_2\}\)”, setting a subscripted scalar equal to a two-element set, where \(y_i\) is a scalar observation everywhere else in the file. And 510 is ungrammatical: “(The documentation also states that when matrices that are near-square,
jax.jacfwdprobably has an edge overjax.jacrev.)”.[qe-writing-003] (reviewer) — Maintain logical flow. Count: 4. Lines: 262, 503, 543, 606. Example: the parameter count contradicts itself three ways. 262 says the conditional distribution “contains 4 (\(k = 4\)) parameters”; 267-272 displays \(\boldsymbol{\beta}\) as \((\beta_0, \beta_1, \beta_2, \beta_3)\), which is four entries and therefore \(k = 3\) under the convention set at 208 (\(\mu_i = \exp(\beta_0 + \beta_1 x_{i1} + \ldots + \beta_k x_{ik})\)); and the simulation immediately below uses five,
\u03b2 = jnp.array([0.26, 0.18, 0.25, -0.1, -0.22])at 221 with five-element \(\mathbf{x}_i\) at 225-228. The Treisman specification the section is building towards has four (const plus the three regressors listed at 686-689, matchingreg1at 704), so 221 is the odd one out and 262’s “\(k = 4\)” is off by one either way. Next, 503 says “To find the gradient of thepoisson_logL” - there is nopoisson_logLanywhere in the file; the function islogL(497). Third, the printed header at 543 labels the parameter column"\u03b8"while everything around it - 536, 551-553, 556, 563 - calls the parameter\u03b2, so the algorithm’s own output uses a symbol the lecture never defines. Fourth, 606-607 says “The iterative process can be visualized in the following diagram, where the maximum is found at \(\beta = 10\)”, but the iterative process the reader has just watched (583) fitted a three-parameter Poisson model, and the diagram at 624-646 draws tangents to the toy quadratic redefined at 611 - two unrelated objects joined by “the following”.[qe-writing-004] — Avoid unnecessary capitalization in narrative text. Count: 2. Lines: 844. Example: mid-sentence ‘Likelihood’.
[qe-writing-005] (reviewer) — Use bold for definitions, italic for emphasis. Count: 2. Lines: 88, 904. Example: only five emphasis spans exist in the file and two of them are the wrong weight. 88 introduces a term in italic where the rule asks for bold - “we need to make an assumption as to which parametric class of distributions is generating the data” - and it is a definition, since 92 then explains what such a class is. 904 does the reverse, bolding a named theorem that is being used rather than defined: “Using the fundamental theorem of calculus, the derivative of a cumulative probability distribution …”. The other three are right: maximum likelihood estimates (99) and Poisson regression (197) are definitions in bold, maximum (444) is emphasis in italic, and Forbes’ (158) is a publication title.
[qe-writing-007] (reviewer) — Use visual elements to enhance understanding. Count: 2. Lines: 557, 624. Example: the Newton-Raphson section makes three claims about the iteration path - 586-587 (“convergence in only 7 iterations”), 589 (“with each iteration, the log-likelihood value increased”) and 594-598 (“the increase in \(\log \mathcal{L}(\boldsymbol{\beta}_{(k)})\) becomes smaller with each iteration … because the gradient is approaching 0”) - and all three are left for the reader to read off the printed table produced at 543-558. The seven log-likelihood values are already in hand; plotting them against \(k\) makes all three claims visible at once and is two lines. Instead the figure that does appear, at 624-646, illustrates a different function (the scalar quadratic redefined at 611) with tangent lines at \(\beta = 7, 8.5, 9.5, 10\) - a good picture of why Newton-Raphson works, but not of the run just performed, which is what 606 says it shows.
Low severity#
None found.
Strengths#
The case convention for densities and distributions (proposed
qe-math-015(proposed)) is right everywhere it appears: lowercase \(f\) for the Poisson pmf (115, 202, 286, 318, 353-360, 870) and for the conditional pmf plotted at 147 and 251, uppercase \(\Phi\) for the normal CDF against lowercase \(\phi\) for its density in the probit exercise (871, 875, 900-901, 908, 916-932), and \(\Phi(s)\) differentiated to \(\phi(s)\) at 908 - the one place where getting the case wrong would break the derivation.The lecture earns its numerical method rather than asserting it: 371-381 derives the Poisson log-likelihood in four displayed steps and then states plainly that “no analytical solution exists to the above problem”, which is what motivates Newton-Raphson at 383-479, and 342-345 justifies working with the log at all by naming the reason (monotone transformation) and giving a one-line example the reader can differentiate mentally.
The Newton-Raphson update is introduced with a picture of its own logic before any code: 395-399 posits a scalar log-likelihood, 401-413 differentiates it with
jax.gradandjax.vmap(each linked to its own documentation page), 415-435 plots the function above its derivative on shared axes, and 438-446 reads the maximum off the pair and adds the second-order check.The JAX machinery is explained where it is used, not assumed: 407-409 says what
jax.gradandjax.vmapdo, and 505-512 quotes the JAX documentation on thejacfwd/jacrevchoice and gives the reason for pickingjacfwdfor the Hessian - so a reader who has not met forward-mode differentiation is not stopped.The empirical section replicates a real published result and shows its work: three nested specifications defined explicitly as column lists (704-724), estimated with the paper’s own robust standard errors (
cov_type="HC0", 735, 772), collected into one table withsummary_coland a fixedregressor_order(776-783), and then turned into the paper’s actual finding - the residual bar chart at 800-831 that puts Russia at the top, with the magnitude stated at 834-835.Both exercises are properly scaffolded and both solutions are complete:
mle_ex1asks for the log-likelihood, gradient and Hessian of the probit model and the solution derives all three (895-933) before writing the class, andmle_ex2supplies \(\mathbf{X}\), \(y\) and \(\boldsymbol{\beta}_{(0)}\) as displayed matrices (968-993) and asks for verification againststatsmodels(995-999) - and 1002-1004 warns that the hand-rolled algorithm is sensitive to starting values, which is the honest caveat.Every code-cell display uses
bmatrix(267-272, 970-976, 979-985, 988-992) -qe-math-003measures zero - and the two equation labels that exist are both used:poissonreg(200) is cited at 684.qe-code-003and all five admonition rules measure zero: the single non-Anaconda dependency is installed in the first code cell with:tags: [hide-output](33-37), the GPU note is factored out into{include} _admonition/gpu.md(24), and both solutions carry:class: dropdown.
Recommended actions#
Settle the parameter count: 262 (“4 (\(k = 4\)) parameters”), the four-entry vector at 267-272, and the five-entry
\u03b2at 221 cannot all be right - the Treisman model 1 that 686-689 and 704 build has four, so 221 and 225-228 should drop to four elements and 262 should say \(k = 3\) under 208’s indexing.Fix the notation defects in the display math:
\mathcal{L(\beta)}to\mathcal{L}(\beta)at 398, 424, 427, 439, 464, 465 and 643;logto\logat 424, 427 and 643; the three misplaced closing parentheses inside\boldsymbol{\beta)}at 918 (once) and 919 (twice);\text{...}for the four prose labels at 686-689; and\text{tol}at 469.Replace the 106
\mathbf/\boldsymbolspans with plain letters perqe-math-004and the 19 apostrophe transposes with^\topperqe-math-002- between them they are the whole reason the Math category scores 3.Correct the two statements of fact: 324-326 should say the likelihood treats \(\boldsymbol{\beta}\) as the argument (not “as a random variable”), and 905 / 911 should say \(\phi\) is the density of the normal, not its “marginal distribution”.
Untangle the notebook state: give the four
logLfunctions distinct names (403, 497, 611, 946), pass the gradient and Hessian intonewton_raphsonrather than readingG_logL/H_logLfrom globals at 550, stop reusing\u03b2for a grid (416, 627) and a loop variable (631), and renamepoisson_logLat 503 to the function that exists.Use the
gammalnalready imported at 66:jnp.log(factorial(y))at 500 overflows well inside the range of the data this lecture plots, and drop the unusedAxes3Dimport at 73.Plot the seven-iteration log-likelihood path from 543-558 so the claims at 586-598 are visible, and either relabel the diagram at 606-607 as an illustration of the method on a scalar example or plot the actual Poisson iteration.
Sweep the figure items:
mystnbcaption and name metadata for the six code-cell figures (127, 175, 217, 415, 624, 800), the sevenfigsize=(12, 8)overrides, lower-case axis labels at 184-185 and 829-830,lw=2at 136, 239 and 635, and the embedded 24-space table title at 785-786.