4

How would I do the following:
With a 3D numpy array I want to take the mean in one dimension and assign the values back to a 3D array with the same shape, with duplicate values of the means in the direction they were derived...
I'm struggling to work out an example in 3D but in 2D (4x4) it would look a bit like this I guess

array[[1, 1, 2, 2]     
      [2, 2, 1, 0]  
      [1, 1, 2, 2]  
      [4, 8, 3, 0]] 

becomes

array[[2, 3, 2, 1]     
      [2, 3, 2, 1]  
      [2, 3, 2, 1]  
      [2, 3, 2, 1]]   

I'm struggling with the np.mean and the loss of dimensions when take an average.

idem
  • 145
  • 1
  • 1
  • 5

4 Answers4

4

You can use the keepdims keyword argument to keep that vanishing dimension, e.g.:

>>> a = np.random.randint(10, size=(4, 4)).astype(np.double)
>>> a
array([[ 7.,  9.,  9.,  7.],
       [ 7.,  1.,  3.,  4.],
       [ 9.,  5.,  9.,  0.],
       [ 6.,  9.,  1.,  5.]])
>>> a[:] = np.mean(a, axis=0, keepdims=True)
>>> a
array([[ 7.25,  6.  ,  5.5 ,  4.  ],
       [ 7.25,  6.  ,  5.5 ,  4.  ],
       [ 7.25,  6.  ,  5.5 ,  4.  ],
       [ 7.25,  6.  ,  5.5 ,  4.  ]])
Jaime
  • 65,696
  • 17
  • 124
  • 159
1

You can resize the array after taking the mean:

In [24]: a = np.array([[1, 1, 2, 2],
[2, 2, 1, 0],
[2, 3, 2, 1],
[4, 8, 3, 0]])
In [25]: np.resize(a.mean(axis=0).astype(int), a.shape)
Out[25]: 
array([[2, 3, 2, 0],
       [2, 3, 2, 0],
       [2, 3, 2, 0],
       [2, 3, 2, 0]])
Ashwini Chaudhary
  • 244,495
  • 58
  • 464
  • 504
1

In order to correctly satisfy the condition that duplicate values of the means appear in the direction they were derived, it's necessary to reshape the mean array to a shape which is broadcastable with the original array.

Specifically, the mean array should have the same shape as the original array except that the length of the dimension along which the mean was taken should be 1.

The following function should work for any shape of array and any number of dimensions:

def fill_mean(arr, axis):
    mean_arr = np.mean(arr, axis=axis)
    mean_shape = list(arr.shape)
    mean_shape[axis] = 1
    mean_arr = mean_arr.reshape(mean_shape)   
    return np.zeros_like(arr) + mean_arr

Here's the function applied to your example array which I've called a:

>>> fill_mean(a, 0)
array([[ 2.25,  3.5 ,  2.  ,  0.75],
       [ 2.25,  3.5 ,  2.  ,  0.75],
       [ 2.25,  3.5 ,  2.  ,  0.75],
       [ 2.25,  3.5 ,  2.  ,  0.75]])

>>> fill_mean(a, 1)
array([[ 1.5 ,  1.5 ,  1.5 ,  1.5 ],
       [ 1.25,  1.25,  1.25,  1.25],
       [ 2.  ,  2.  ,  2.  ,  2.  ],
       [ 3.75,  3.75,  3.75,  3.75]])
Alex Riley
  • 169,130
  • 45
  • 262
  • 238
  • Only answer that obeys the generality of the question and not the specific problem reported as an example. I appreciated also the abstraction provided by defining a function. – gboffi Dec 17 '14 at 11:18
  • Thanks - although Jaime's recent answer does what mine does much more neatly with `keepdims` (making my method somewhat redundant :-) ) – Alex Riley Dec 17 '14 at 16:01
0

Construct the numpy array

import numpy as np
data = np.array(
    [[1, 1, 2, 2],
     [2, 2, 1, 0],
     [1, 1, 2, 2],
     [4, 8, 3, 0]]
)

Use the axis parameter to get means along a particular axis

>>> means = np.mean(data, axis=0)
>>> means
array([ 2.,  3.,  2.,  1.])

Now tile that resulting array into the shape of the original

>>> print np.tile(means, (4,1))
[[ 2.  3.  2.  1.]
 [ 2.  3.  2.  1.]
 [ 2.  3.  2.  1.]
 [ 2.  3.  2.  1.]]

You can replace the 4,1 with parameters from data.shape

Kevin Campbell
  • 629
  • 7
  • 5