Skip to content

v0.1.4 — statistical-correctness fixes

Choose a tag to compare

@jturner-uofl jturner-uofl released this 26 May 12:30
· 37 commits to main since this release

[0.1.4] — 2026-05-26

Fixed (statistical correctness)

  • regrid_response(em, bias_adjust=True) on a GLM with a
    non-identity link now raises ValueError unless an explicit
    sigma= is supplied. The previous default (info.scale) used
    the residual dispersion on the response scale as the Jensen
    correction's σ² — which silently inflated the response-scale
    EMM by a family-dependent factor (1.5× on canonical Poisson(log),
    ~3.25× on Gaussian(log)). R emmeans::summary(..., bias.adjust=TRUE) enforces the same constraint. OLS with an
    LHS transform (lm(log(y) ~ ...)) is unchanged — info.scale
    there is the correct sigma².
  • Cox PH emmeans(fit, ..., type='link') now emits a
    UserWarning advising that the emmean column is on the
    relative log-hazard scale (the partial likelihood does not
    identify the baseline hazard, so the reference-level row shows
    emmean=0 by construction). pairs(emm) and regrid_response(emm)
    remain identifiable and unchanged. R emmeans.coxph omits the
    link-scale column for the same reason.
  • apply_kenward_roger is now idempotent: a second call on an
    already-KR-corrected EMM/contrast returns the input unchanged.
    Previously a second application recomputed K-R from the
    already-inflated vcov and drifted the df by ~0.05 due to finite-
    difference noise on the doubly-corrected Hessian.

Fixed (API)

  • joint_tests(emm_result) now accepts EMMResult /
    ContrastResult / RefGrid input by dispatching to the underlying
    model_info, matching R emmeans::joint_tests behaviour.
    Previously raised TypeError: No adapter recognises EMMResult.
  • pairs(emm) now emits a UserWarning when the input EMM
    contains any non-estimable rows (emmean is NaN, typically from
    a rank-deficient design). Contrasts touching those rows still
    propagate NaN to the result — the warning surfaces the issue so
    users are not surprised by silent NaN downstream. R emmeans
    marks these as nonEst; pymmeans flags them at the contrast
    step.

Fixed (documentation)

  • apply_satterthwaite docstring now documents the per-row
    property of Satterthwaite df: df at an EMM cell can differ from
    df on a pair contrast by an order of magnitude on the same model
    (different linear-combination matrix L), and both are correct.
    Includes the canonical sleepstudy numbers (EMM at Days=9
    df ≈ 23.4, Days=9 − Days=0 contrast → df ≈ 161).
  • survey.py module docstring now matches the implementation
    for the simple-random-sample variance (the code applies the
    n/(n−1) finite-sample correction with score centring; the
    docstring previously cited the EHW uncentred form, which agrees
    at the MLE FOC but diverges if the GLM has not fully converged).
  • _regularize_corr_for_mvt docstring no longer claims R's
    mvtnorm::pmvt does "the same thing internally" — R uses
    Cholesky pivoting and dimension reduction; pymmeans uses a
    ridge that introduces an O(1e-9) bias invisible at the 1e-4
    validation tolerance.

Deferred to 0.2.0

  • Kenward-Roger algorithmic refactor (analytic derivatives or
    chunked finite-difference) for memory-bounded n_theta ≥ 20
    fits. Current implementation works for typical mixed-model
    sizes (n_theta ≤ ~10).
  • Hessian-step Richardson extrapolation for poorly-scaled fits
    (heritability-like parameters ≈ 1e-3). Current step formula is
    adequate for the canonical reference suite but accumulates
    10-50 % roundoff at extreme parameter scales.