Numpy: create fine-copied array of python objects

I have a list of objects namedtuple

that I would like to place in an array numpy

, so I can use its handy index assignment operations. Consider an input like this,

In [3]: Point = namedtuple("Point", ["x", "y"])
In [4]: x_lst = [Point(1, 2), Point(3, 4)]

      

By default numpy will create 2D arrays from its input,

In [5]: numpy.array(x_lst)
Out[5]:
array([[1, 2],
       [3, 4]])

In [6]: numpy.array(x_lst).shape
Out[6]: (2, 2)

      

It is possible to suppress this to some extent with the record type, but it still does some manipulation on the type of its input (in this case, each element is bound to a regular tuple).

In [7]: numpy.core.records.array(x_lst)
Out[7]:
rec.array([(1, 2), (3, 4)],
      dtype=[('f0', '<i8'), ('f1', '<i8')])

      

I managed to get around the problem like this,

In [8]: result = numpy.full((2,), None, dtype=object)
In [9]: result[:] = x_lst

In [10]: type(result[0])
Out[10]: __main__.Point

      

but that seems less elegant. Anyone have a better solution?

+3


source to share


1 answer


I would use

In [1152]: xx=np.empty((2,),dtype=object)
In [1153]: xx[:] = x_lst
In [1154]: xx
Out[1154]: array([Point(x=1, y=2), Point(x=3, y=4)], dtype=object)

      

But yes, this is essentially the same as your decision.

I've observed in other SO questions that creating arrays of objects usually requires some deception. np.array()

by default tries to create the largest dimensional numeric array it can retrieve from the data. Namedtuple your object is iterable (this is one of its functions) [i for i in Point(1,2)]

, so np.array

x_lst

looks the same as a list of tuples: [(1,2),(3,4)]

.

Creating an empty array of objects and filling it with using [:]

seems to be the simplest solution.

Since points are iterable, various operations on this array can be unpredictable. For example:



In [1198]: xx.sum()
Out[1198]: (1, 2, 3, 4)

      

If the class is not iterable, creating an array of objects is easier:

In [1179]: class MyObject(object):
    def __init__(self, *args):
        self.args=args
   ......:         

In [1180]: yy=np.array([MyObject(1,2),MyObject(1,2,3)])

In [1181]: yy
Out[1181]: 
array([<__main__.MyObject object at 0xb18e0a8c>,
       <__main__.MyObject object at 0xb18e0aac>], dtype=object)

In [1182]: yy[0].args
Out[1182]: (1, 2)

      

Ditto for lists or tuples with different sizes, which it cannot force into a 2d array:

In [1183]: np.array([(1,2),(1,2,3)])
Out[1183]: array([(1, 2), (1, 2, 3)], dtype=object)

      

In any of these elements, the elements can be replaced after creation with your points.

+1


source







All Articles