Reputation: 2044
I am trying to subtract the minimum value of an ndarray for an arbitrary dimension. It seems to work with 3 dimensions, but not 4
3 Dimensional Case:
x1 = np.arange(27.0).reshape((3, 3, 3))
# x1 is (3,3,3)
x2 = x1.min(axis=(1,2))
# x2 is (3,)
(x1 - x2).shape
#Output: (3, 3, 3)
(x1 - x2).shape == x1.shape
#As expected: True
4 Dimnesional Case:
mat1 = np.random.rand(10,5,2,1)
# mat1 is (10,5,2,1)
mat2 = mat1.min(axis = (1,2,3))
# mat2 is (10,)
(mat1 - mat2).shape == mat1.shape
# Should be True, but
#Output: False
Upvotes: 0
Views: 23
Reputation: 231385
Your first example is misleading because all dimensions are the same size. That hides the kind of error that you see in the 2nd. Examples with different size dimensions are better at catching errors:
In [530]: x1 = np.arange(2*3*4).reshape(2,3,4)
In [531]: x2 = x1.min(axis=(1,2))
In [532]: x2.shape
Out[532]: (2,)
In [533]: x1-x2
...
ValueError: operands could not be broadcast together with shapes (2,3,4) (2,)
Compare that with a case where I tell it to keep dimensions:
In [534]: x2 = x1.min(axis=(1,2),keepdims=True)
In [535]: x2.shape
Out[535]: (2, 1, 1)
In [536]: x1-x2
Out[536]:
array([[[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]],
[[ 0, 1, 2, 3],
[ 4, 5, 6, 7],
[ 8, 9, 10, 11]]])
The basic rule of broadcasting: a (2,) array can expand to (1,1,2) if needed, but not to (2,1,1).
But why doesn't the 2nd case produce an error?
In [539]: mat1.shape
Out[539]: (10, 5, 2, 1)
In [540]: mat2.shape
Out[540]: (10,)
In [541]: (mat1-mat2).shape
Out[541]: (10, 5, 2, 10)
It's that trailing size 1, which can broadcast with the (10,):
(10,5,2,1) (10,) => (10,5,2,1)(1,1,1,10) => (10,5,2,10)
It's as though you'd added a newaxis
to a 3d array:
mat1 = np.random.rand(10,5,2)
mat1[...,None] - mat2
Upvotes: 2