简体   繁体   中英

Numpy ndarray subclass - forcing reshape in __array_finalize__

I am having trouble with the following:

I would like to write an ndarray subclass and enforce shape (-1,3) for any new instance of this subclass, whichever way it comes about- explicit constructor, view casting or from template.

I've tried loads of things but none seem to work. I reckon I haven't fully grasped the underlying process. Any help is much appreciated!

import numpy as np

class test(np.ndarray):
def __new__(cls, *args, **kwargs):
    return np.ndarray.__new__(cls, *args, **kwargs)

def __array_finalize__(self, obj):

#        self.resize(-1,3)
#        self.reshape(-1,3)
#        self=self.reshape(-1,3)
        np.reshape(self,(-1,3))

a=np.array([1,2,3])
b=a.view(test)
c=test(a)
d=a.reshape(-1,3)
print '+++++++'
print a.shape,a
print '+++++++'
print b.shape,b
print '+++++++'
print c.shape,c
print '+++++++'
print d.shape,d

To clarify what I am trying to do:

I have vector fields which I want to treat generically as 3D, hence the (:,3) shape and (-1,3) shape resizing. I am looking for a pure object oriented solution to implement essentially a few additional methods to complement what already comes with NumPy.

For example, I've started writing some stuff purely with ndarrays, but the code would be much more readable if I could just write

normalizedVector = ndarray.view(my3DVectorClass).normalize()

rather than

normalizedVector = ndarray / ( sum(ndarray**2, axis=1)**0.5 )

My problems with the second:

  • I would like to be able to not have to worry about whether or not I am asking for the normalized version of a shape (3,) or (:,3) array.
  • I would like to be able to use pure linear algebra terminology inside the classes method implementations and not have to bother with indexing and error/dimension checking within method definitions

I guess you could argue to just work with instances of my3DVectorClass exclusively but I would then have to do the reverse view casting when using all of the SciPy machinery, since they expect ndarray if I'm not mistaken, which would make these parts of the code a little bloated.

If I might have my logic wrong somehow I am grateful for suggestions. I'm still very much on the learning curve for both OOP and SciPy/NumPy.

Thanks a lot already!

Markus

You should take a look at how the matrix class is implemented. It does similar tricks to maintain ndims=2 .

However, I and many others consider such trickery more trouble than it is worth. The matrix class has caused a lot of problems in the past because it only partly acts like a normal ndarray . Consider writing functions instead. The code example you give above would be the most readable like so: normalizedVector = normalize(ndarray) . Making more subclasses is not always the best design, even when using object-oriented style.

reshape will try to create a view of the data with the new shape, and if it can't it will create a copy of your data with the new shape. But the original object is left unchanged. To modify the shape in-place, you can do:

self.shape = (-1, 3)

For example:

>>> a = np.arange(9)
>>> a
array([0, 1, 2, 3, 4, 5, 6, 7, 8])
>>> np.reshape(a, (-1, 3)) # creates a view with the new shape
array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]])
>>> a # but the original object is unchanged
array([0, 1, 2, 3, 4, 5, 6, 7, 8])
>>> a.shape = (-1, 3) # this modifies the original object
>>> a
array([[0, 1, 2],
       [3, 4, 5],
       [6, 7, 8]])

You have to be careful though, because if it cannot be reshaped without making a copy, it will raise an AttributeError :

>>> a = np.arange(36).reshape(6, 6).T
>>> b = np.reshape(a, (-1, 3)) # creates a copy of the data in a
>>> a.shape = (-1, 3) # tries to reshape in-place, and fails
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: incompatible shape for a non-contiguous array

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM