Skip to content

Fix matchindex() tie breaking#758

Open
stefvanbuuren wants to merge 2 commits into
masterfrom
fix/matchindex-tie-breaking
Open

Fix matchindex() tie breaking#758
stefvanbuuren wants to merge 2 commits into
masterfrom
fix/matchindex-tie-breaking

Conversation

@stefvanbuuren

Copy link
Copy Markdown
Member

Fixes miscalibrated donor selection in matchindex(), the default PMM matching engine since mice 3.11.8, when many target cases share the same (or nearly the same) predicted value — e.g. intercept-only models, few categorical predictors, or heavily rounded outcomes.

Root cause: ties among donors were broken once per call (once per imputed dataset), so all tied target cases drew from the same fixed donor subset within one completed dataset, inflating between-imputation variance and producing overly conservative CIs under Rubin's rules.

Fix: after the existing sort, contiguous tie blocks are identified once; each target's tie-breaking is now resolved independently, either via a fast uniform draw (when the near block already has ≥ k donors) or per-step reservoir sampling within blocks smaller than k.

Closes #757. See also the original discussion in #236.

Testing: added tests/testthat/test-matchindex.R (14 tests, verified to fail 2/14 against the pre-fix code); full existing PMM suite passes; calibration checked via simulation (coverage ~98% vs. ~100% pre-fix, ~0% for the legacy matcher() on the same tied-donor scenario).

Opening on a feature branch to gather feedback/testing from users before merging, given the statistical sensitivity of this change.

Previously, matchindex() shuffled the donor pool once per call, so all
target cases sharing the same (or nearly the same) predicted value drew
from the same fixed subset of donors within one imputed dataset. This
inflated between-imputation variance and produced overly conservative
confidence intervals under Rubin's rules, most visibly in intercept-only
PMM models and models with few categorical predictors.

Ties among donors are now broken independently for each target case:
after the existing one-time sort, contiguous tie blocks are identified,
and when a target's k-nearest-neighbour window falls inside a block,
either a fast uniform draw (block >= k) or per-step reservoir sampling
(block < k) is used instead of the old fixed shuffle order.

See #757, following up on the discussion in #236.
- Update matchindex() roxygen (and regenerated RcppExports.R /
  matchindex.Rd) to describe the tie-block detection, the fast path
  for large tie blocks, and the historical bug fixed in #757.
- Note in mice.impute.pmm()'s use.matcher docs that the legacy
  matcher() is itself miscalibrated on tied donors, so it should only
  be used to reproduce results from older mice versions, not as a
  "safe" fallback.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

PMM donor selection is miscalibrated when the predicted metric is (nearly) tied across cases, in both matchindex() and matcher()

1 participant