0

It is possible to compute the average of a numpy array over multiple dimensions, as in eg. my_ndarray.mean(axis=(1,2)).

However, it does not seem to work with a masked array:

>>> import numpy as np
>>> a = np.random.randint(0, 10, (2, 2, 2))
>>> a
array([[[0, 9],
        [2, 5]],

       [[8, 6],
        [0, 7]]])
>>> a.mean(axis=(1, 2))
array([ 4.  ,  5.25])
>>> ma = np.ma.array(a, mask=(a < 5))
>>> ma.mean(axis=(1, 2))
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python2.7/site-packages/numpy/ma/core.py", line 5066, in mean
    cnt = self.count(axis=axis)
  File "/usr/lib/python2.7/site-packages/numpy/ma/core.py", line 4280, in count
    n1 = np.size(m, axis)
  File "/usr/lib/python2.7/site-packages/numpy/core/fromnumeric.py", line 2700, in size
    return a.shape[axis]
TypeError: tuple indices must be integers, not tuple

How can I compute the average of a masked array over multiple axis, preferably as simply as it would be for a normal array?

(I would rather use a solution that does not implies defining a new function, as proposed in this answer.)

Community
  • 1
  • 1
Arcturus B
  • 5,181
  • 4
  • 31
  • 51
  • Have you tried `ma.mean(2).mean(1)`? – wflynny Apr 20 '16 at 15:29
  • @wflynny : This answer should work. In case, that he only wants to compute the average of the 'not-masked-values'. – fuuman Apr 20 '16 at 15:33
  • For more details on the tuple indexing not being implemented see [this question](http://stackoverflow.com/questions/30209624/numpy-mean-used-with-a-tuple-as-axis-argument-not-working-with-a-masked-arr), too. – mtzl Apr 20 '16 at 15:37
  • @wflynny: this was my first guess but it changes the weight given to each value. With the previous eg. it returns `[7, 7.25]` instead of `[7, 7]` as it should. (Plus, it would be `ma.mean(1).mean(1)`.) – Arcturus B Apr 20 '16 at 15:42

2 Answers2

2

I found out that though np.ma.mean does not works, np.ma.average gives the expected result:

>>> np.ma.average(ma, axis=(1,2))
masked_array(data = [7.0 7.0],
             mask = [False False],
       fill_value = 1e+20)

This is confusing since for regular array, np.average is a mere wrapper around np.mean. But as long as it works, I won’t complain!

Arcturus B
  • 5,181
  • 4
  • 31
  • 51
0

You can reshape it before the mean :

>>>ma.reshape(mc.shape[0],-1).mean(1)
masked_array(data = [1.6666666666666667 4.0],
         mask = [False False],
         fill_value = 1e+20)

Note that partial application of averaging lead to ambiguous results :

>>> ma.mean(1).mean(1)
masked_array(data = [1.5 4.0],
             mask = [False False],
       fill_value = 1e+20)


>>> ma.mean(2).mean(1)
masked_array(data = [2.25 4.0],
             mask = [False False],
       fill_value = 1e+20)

Explained by :

>>>ma
masked_array(data =
 [[[0 1]
  [4 --]]

 [[-- --]
  [-- 4]]],
             mask =
 [[[False False]
  [False  True]]

 [[ True  True]
  [ True False]]],
       fill_value = 999999)

The weights are not the same in each case.

To average on other dimensions, you can use np.rollaxis before.

B. M.
  • 18,243
  • 2
  • 35
  • 54