Home > Net >  Convert list of objects to numpy array without coercing objects into array
Convert list of objects to numpy array without coercing objects into array

Time:04-28

I want to turn a Python list of objects into a numpy array of objects for easier manipulation of the list, e.g. index slicing, etc. However, numpy coerces list-like objects into arrays during conversion

import numpy as np
class ListLike(object):
    def __init__(self, list):
        self.list = list
        self.otherdata = 'foo'
    def __getitem__(self, i):
        return self.list[i]
    def __len__(self):
        return len(self.list)
o1 = ListLike([1,2])
o2 = ListLike([3,4])
listOfObj = [o1, o2]
numpyArray = np.array(listOfObj)

>>> numpyArray
array([[1, 2],
       [3, 4]])
>>> type(numpyArray[0])
<class 'numpy.ndarray'>

This means I lose the objects and other data and methods associated with them

>>> numpyArray[0].otherdata
AttributeError: 'numpy.ndarray' object has no attribute 'otherdata'

How do I get this result instead?

>>> numpyArray
array([(<__main__.ListLike object at 0x000000002786DAF0>, <__main__.ListLike object at 0x000000002E56B700>)], dtype=object)
>>> type(numpyArray[0])
<class '__main__.ListLike'>

It would be even better if I could also control the depth of the coersion with something like this

o3 = ListLike([o1,o2])
numpyArray = np.array([o3, o3], depth=1)

>>> numpyArray
array([[(<__main__.ListLike object at 0x000000002786DAF0>, <__main__.ListLike object at 0x000000002E56B700>)], [(<__main__.ListLike object at 0x000000002786DAF0>, <__main__.ListLike object at 0x000000002E56B700>)]], dtype=object)

CodePudding user response:

In [35]: arr = np.empty(2, object)
In [36]: arr[:] = listOfObj
In [37]: arr
Out[37]: 
array([<__main__.ListLike object at 0x7f3b9c6f1df0>,
       <__main__.ListLike object at 0x7f3b9c6f19d0>], dtype=object)

Element methods/attributes have to be accessed with a list comprehension, just as with the list:

In [39]: arr[0].otherdata
Out[39]: 'foo'
In [40]: [a.otherdata for a in listOfObj]
Out[40]: ['foo', 'foo']
In [41]: [a.otherdata for a in arr]
Out[41]: ['foo', 'foo']

frompyfunc could also be used for this, though timing is about the same:

In [44]: np.frompyfunc(lambda a: a.otherdata,1,1)(arr)
Out[44]: array(['foo', 'foo'], dtype=object)

CodePudding user response:

I think that you wish achieve this:

class ListLike(np.array):
    def __init__(self, _list):
        super().__init__(_list)
        self.otherdata = 'foo'

But you can't subclass from a builtin_function.

Instead i've managed to write

class ListLike(object):
    def __init__(self, _list):
        self._list = _list
        self.otherdata = 'foo'
    def __getitem__(self, key): return self._list[key]
    def __str__(self): return self._list.__str__()
    #Note 1
    #def __len__(self): return self._list.__len__()

tested with:

o1 = ListLike([1,2])
o2 = ListLike([3,4])
numpyArray = np.array([o1, o2], dtype=object)      
#Note 2
#numpyArray = np.array([o1, o2, 888], dtype=object) 
print(numpyArray[0], numpyArray[0].otherdata, end='.\t')
print("Expected: [1,2] foo")

Note 1

This works as long as you don't implement __len__ method for LikeList class.

Note 2

If you insist, then append some kind of sorcery to this line.

  1. An empty item as: '',None, []
  2. An instance of another dim as: LikeList([7])
  3. Another object as: 5, ... (Ellipsis) , 'hello', 0.1

(i couldn't figure it out, why np.array doesn't detect dtype=object)

  • Related