Reputation: 4706
Some numpy functions (logically) return scalars:
>>> my_arr = np.ndarray(shape=(1,))
>>> type(np.max(my_arr))
<type 'numpy.float64'>
but only when called with an ndarray, rather than a subclass:
>>> class CustomArray(np.ndarray):
... pass
>>> my_arr = CustomArray(shape=(1,))
>>> type(np.max(my_arr))
<class '__main__.CustomArray'>
Why is this? I'd expect either both to return a scalar (of type <type 'numpy.float64'>
, or the former to return a np.ndarray
instance and the latter a CustomArray
instance. But instead, I get a combination of these two behaviours. Can I change this behaviour through changing my own class?
I don't see anything that would explain this on the doc page discussing subclassing ndarray (http://docs.scipy.org/doc/numpy-1.9.2/user/basics.subclassing.html).
(Running Python 2.7.10, numpy 1.9.2, in case it matters.)
Upvotes: 4
Views: 1142
Reputation: 415
I also ran into this, solved it for all aggregation/reduction operations in NumPy by implementing a custom __array_wrap__
:
import numpy as np
class CustomArray(np.ndarray):
def __array_wrap__(self, obj, **kwargs):
if obj.shape == ():
return obj[()]
else:
return super().__array_wrap__(obj, **kwargs)
Example return types for various operations:
>>> a = CustomArray(shape=(3,))
>>> type(np.max(a))
<class 'numpy.float64'>
>>> type(np.median(a))
<class 'numpy.float64'>
>>> type(np.exp(a))
<class '__main__.CustomArray'>
>>>
Upvotes: 0
Reputation: 5068
This is because max()
is not overloaded in CustomArray
. If you try it, my_array.max()
returns an object of CustomArray instead of scalar.
my_array = CustomArray(shape=(1,))
print my_array.max()
>> CustomArray(9.223372036854776e+18)
np.max
internally calls np.amax
, which ends up calling np.maximum.reduce
. This is the standard reduce
of map-reduce and returns a base-object returned by max. Hence, the type returned by np.max
is in fact the type returned by max()
method called on your object. You can override it as:
class CustomArray(np.ndarray):
def max(self, axis, out):
return np.ndarray(self.shape, buffer=self).max(axis, out)
type(np.max(my_arr))
>> numpy.float64
The trick is to upcast self as an np.ndarray
and find max using it.
Upvotes: 1