Skip to content
Work Practice Products Coding interviews Machine learning coding Quant developer HFT course Blog Method Why me About Book a call

ML coding · Statistical inference

McNemar's test: is the new model really better?

Easy · Target 15 minutes · Python and NumPy · Type asked at

You get the true labels y and what two models a and b predicted for the same examples. I'll call nab the number of examples where A is right and B is wrong and nba the number where it's the other way round. If the two models are really as good as each other then every one of those disagreements is as likely to go to A as to B, so it's like flipping n = nab + nba fair coins. Your function should return the exact two-sided p-value, which is the chance of getting a split that's at least as lopsided as the one you actually saw. When the two models never disagree there's nothing to test and you should return 1.

Examples

Input y = [1, 0, 1, 1, 0, 1], a = [1, 0, 0, 1, 0, 1], b = [1, 1, 1, 0, 0, 1]

Output 1

B wins one disagreement and A wins two, and you can't split three flips any more evenly than that, so it's 1.

Input y = [0, 0, 0, 0, 0], a = [0, 0, 0, 0, 0], b = [1, 1, 1, 1, 1]

Output 0.0625

A wins all five, and the chance of five heads or five tails in five flips is 2/32, so you'd return 0.0625.

Input y = [2, 1, 0], a = [2, 1, 0], b = [2, 1, 0]

Output 1

They agree on every example so you've got nothing to go on, and that's a 1.

Constraints

  • 1 ≤ len(y) = len(a) = len(b) ≤ 2000
  • Labels are integers (any number of classes)
  • Checked to an absolute tolerance of 10⁻¹²

Hints

Hint 1

If both models got an example right, or both got it wrong, it can't tell you which one is better, so I'd just skip it.

Hint 2

When the models are equally good each disagreement goes to A with probability a half, so n_ab is Binomial(n, 1/2) and that's all you need.

Hint 3

Because that distribution is symmetric you can work out the smaller tail and double it, as long as you don't let it go over 1.

Where candidates go wrong

  • I see a lot of people put the two accuracies into an unpaired test, which throws the pairing away, and when the models agree on most examples it almost never finds anything.
  • The chi-squared version is fine when you've got lots of disagreements, but under about 25 it's a poor approximation and the exact sum doesn't cost you anything anyway.
  • With more than two classes both models can be wrong in different ways. That still counts as both wrong and not as a disagreement, because you compare each prediction with y and not with each other.
  • If n_ab and n_ba are equal then doubling the tail gives you more than 1, so you have to cap it.
Console⌘/Ctrl + Enter runs

Python runs in your browser with NumPy. The first run downloads the runtime, which takes a few seconds.


Why interviewers ask it

Anyone who has shipped a model has had to say whether a two point gain on the eval set was real. This checks that you know the two runs are paired and that only the questions where they disagree carry any information. Most people compare the two accuracies as if they came from separate samples and get a test that's much too weak.

The theory behind it is in the lesson Statistical inference in code: standard errors, permutation tests, the Kalman filter.


Keep going