110

Is there a method in numpy for calculating the Mean Squared Error between two matrices?

I've tried searching but found none. Is it under a different name?

If there isn't, how do you overcome this? Do you write it yourself or use a different lib?

Saullo G. P. Castro
  • 56,802
  • 26
  • 179
  • 234
TheMeaningfulEngineer
  • 15,679
  • 27
  • 85
  • 143
  • 14
    `((A - B) ** 2).mean(axis=ax)`, where `ax=0` is per-column, `ax=1` is per-row and `ax=None` gives a grand total. – Fred Foo May 27 '13 at 14:13
  • 2
    If you formulate that as an answer I will accept it. – TheMeaningfulEngineer May 27 '13 at 22:21
  • 1
    This answer is not correct because when you square a numpy matrix, it will perform a matrix multiplication rathar square each element individualy. Check my comment in Saullo Castro's answer. (PS: I've tested it using Python 2.7.5 and Numpy 1.7.1) – renatov Apr 19 '14 at 18:23
  • Also just as a note for anyone looking at this in the context of neural networks, you should sum the error, not average. Averaging the error will give you incorrect gradient values if you try to do grad checking (unless you account in backprop for the average, which is more work than it's worth) – Recessive Jan 28 '20 at 06:08

7 Answers7

150

You can use:

mse = ((A - B)**2).mean(axis=ax)

Or

mse = (np.square(A - B)).mean(axis=ax)
  • with ax=0 the average is performed along the row, for each column, returning an array
  • with ax=1 the average is performed along the column, for each row, returning an array
  • with omitting the ax parameter (or setting it to ax=None) the average is performed element-wise along the array, returning a scalar value
Saullo G. P. Castro
  • 56,802
  • 26
  • 179
  • 234
  • 3
    Correct if I'm wrong, but I think if you do (MatrixA - MatrixB) ** 2 it will try to perform a matrix multiplication, which is different than square each element individually. If you try to use the following formula with a non-square matrix, it will raise a ValueError. – renatov Apr 04 '14 at 20:12
  • @renatov in a Numpy array this formula will be applied element-wise so that no matrix multiplication is performed – Saullo G. P. Castro Apr 04 '14 at 20:20
  • @Saulo Castro, I've just tested and I must insist that the result will not be element-wise. I'm using Python 2.7.5 and Numpy 1.7.1. I created the matrix "a" and squared it usign the following commands: `a = numpy.matrix([[5, 5], [5, 5]])` and then `a ** 2`. The result is the numpy matrix `matrix([[50, 50], [50, 50]])`, which shows that numpy matrix multiplication will **not** be element-wise. – renatov Apr 19 '14 at 18:19
  • 8
    @renatov maybe you misunderstood me, using a `np.ndarray` will do an element-wise multiplication for `a**2`, but using a `np.matrixlib.defmatrix.matrix` will do a matrix multiplication for `a**2`... – Saullo G. P. Castro Apr 21 '14 at 18:41
  • 2
    Sorry, I misunderstood you. I thought you were using numpy.matrix. – renatov Apr 21 '14 at 19:06
  • 1
    Bear in mind that if you're comparing 2 uint matricies, this will not work because the difference will have negative numbers. You'll need to make int copies before hand (`Acmp = np.array(A, dtype=int)`) – Charles L. Nov 01 '15 at 21:02
  • 4
    `np.nanmean(((A - B) ** 2))` if missing values – Sam Weisenthal Dec 04 '16 at 01:48
  • The first solution looks like numpy array syntax too, but it is not (see comment by Saullo Castro), so this very specific starting assumption (using a np.matrix) needs to be part of the answer, otherwise it is really misleading. – fotis j May 15 '19 at 15:24
  • Is it possible to have an MSE between two 2D arrays that is equal to 263.562. – asendjasni Oct 27 '19 at 10:50
50

This isn't part of numpy, but it will work with numpy.ndarray objects. A numpy.matrix can be converted to a numpy.ndarray and a numpy.ndarray can be converted to a numpy.matrix.

from sklearn.metrics import mean_squared_error
mse = mean_squared_error(A, B)

See Scikit Learn mean_squared_error for documentation on how to control axis.

Charity Leschinski
  • 2,886
  • 2
  • 23
  • 40
35

Even more numpy

np.square(np.subtract(A, B)).mean()
Mark Swardstrom
  • 17,217
  • 6
  • 62
  • 70
9

Just for kicks

mse = (np.linalg.norm(A-B)**2)/len(A)
desertnaut
  • 57,590
  • 26
  • 140
  • 166
dcneuro
  • 181
  • 2
  • 6
6

Another alternative to the accepted answer that avoids any issues with matrix multiplication:

 def MSE(Y, YH):
     return np.square(Y - YH).mean()

From the documents for np.square:

Return the element-wise square of the input.
desertnaut
  • 57,590
  • 26
  • 140
  • 166
2

The standard numpy methods for calculation mean squared error (variance) and its square root (standard deviation) are numpy.var() and numpy.std(), see here and here. They apply to matrices and have the same syntax as numpy.mean().

I suppose that the question and the preceding answers might have been posted before these functions became available.

Remarks on statistics
To answer the comment made by @Drew :
This answer is equivalent to the top answers in this thread. Technically, MSE differs from variance in that it uses "true" value of the parameter, rather than its estimate, see What's the difference between the variance and the mean squared error? and What is the Difference between Variance and MSE?. The two quantities then differ by the bias of our estimate of the central parameter. However, when calculating sample variance, as is done in the OP, we cannot really know the value of this parameter. I believe the OP uses term MSE in a loose sense.

Furthermore, the numpy functions proposed above allow for parameter ddof (the number of degrees of freedom), which allows to obtain unbiased variance estimates (contrary to what is claimed in some superficial comparisons between python and R.)

Roger Vadim
  • 373
  • 2
  • 12
  • MSE and variance are not the same unless the mean is zero (i.e., unless A and B have the same mean so that A-B has mean zero in the calculations above). – Drew Nov 02 '20 at 21:04
0

What about this to keep with the np.operation style?

mse = np.mean(np.square(A - B))

Just keep in mind that np.mean() with no axis keyword argument specified will output a scalar, just like np.sum().