Skip to content Skip to sidebar Skip to footer

Maintaining Numpy Subclass Inside A Container After Applying Ufunc

I have created a class derived from numpy's ndarray following numpy's documentation, and it looks like (reduce the number of attributes to make it more readable): import numpy as

Solution 1:

There's no such thing as dtype=Atom3D. The same goes for dtype=list and dtype=np.ndarray. It creates a dtype=object array, where each element is a pointer to objects elsewhere in memory.

Creating an object array with np.array(...) can be tricky. np.array evaluates the entries and makes some of its own choices. The best bet, if you want absolute control over the elements that go into an object array is to create an 'blank' one, and assign elements yourself.

In [508]: A=np.array([np.matrix([1,2]),np.matrix([2,1])],dtype=object)

In [509]: A       # a 3d array, no matrix subarrays
Out[509]: 
array([[[1, 2]],

       [[2, 1]]], dtype=object)

In [510]: A=np.empty((2,),dtype=object)

In [511]: A
Out[511]: array([None, None], dtype=object)

In [512]: A[:]=[np.matrix([1,2]),np.matrix([2,1])]

In [513]: A
Out[513]: array([matrix([[1, 2]]), matrix([[2, 1]])], dtype=object)

Unless you really need the object array for things like reshaping and transposing, you are usually better off working with a list.

Mixing the object types also works:

In [522]: A=np.asarray([np.matrix([1,2]),np.ma.masked_array([2,1])],dtype=np.object)

In [523]: A
Out[523]: 
array([matrix([[1, 2]]),
       masked_array(data = [21],
             mask = False,
       fill_value = 999999)
], dtype=object)

==========================

When you do np.dot([a1,a2,a3],m), it first turns any lists into an array with np.asarray([a1,a2,a3]). The result is a 2d array, not an array of Atom3d objects. So the dot is the usual array dot.

If I create an object array as I suggested:

In [14]: A=np.empty((3,),dtype=object)
In [16]: A[:]=[a1,a2,a1+a2]

In [17]: A
Out[17]: 
array([1: (   5.000,    5.000,     5.000),
       1: (   5.000,    5.000,     5.000),
       1: (  10.000,   10.000,    10.000)], dtype=object)

In [18]: np.dot(A,m)
Out[18]: 
array([1: (   5.000,    5.000,     5.000),
       1: (   5.000,    5.000,     5.000),
       1: (  10.000,   10.000,    10.000)], dtype=object)

Atom3D type is preserved;

Same for subtraction:

In [23]: A- np.array([3.,2., 0])
Out[23]: 
array([1: (   2.000,    2.000,     2.000),
       1: (   3.000,    3.000,     3.000),
       1: (  10.000,   10.000,    10.000)], dtype=object)

Addition of that array and an Atom3D works, though there is something wrong with displaying the result:

In [39]: x = A + a2

In [40]: x
Out[40]: <repr(<__main__.Atom3D at 0xb5062294>) failed: TypeError: non-empty format string passed to object.__format__>

Calculations with object dtype arrays are iffy. Some work, apparently by iterating over the elements of the array, applying the function, and turning the result back into an object array. In effect an array version of

 [func(a, x)for a in A]

Even if it works, it isn't performing a fast compiled operation; it is iterative (timings will be similar to the list equivalent).

Other things don't work

In[41]: a1>0Out[41]: 1: (   1.000,    1.000,     1.000)

In[42]: A>0
...
ValueError: Thetruthvalueofanarraywithmorethanoneelementisambiguous. Usea.any() ora.all()

We've pointed out many times that object dtype arrays are little more than glorified lists. The elements are pointers as with lists, and thus operations will involve iterating over those pointers - in Python, not C. This is not a highly developed corner of numpy code.

Post a Comment for "Maintaining Numpy Subclass Inside A Container After Applying Ufunc"