将对象列表转换为 numpy 数组而不将对象强制转换为数组

Convert list of objects to numpy array without coercing objects into array

我想将一个 Python 对象列表转换为一个 numpy 对象数组,以便于对列表进行操作,例如索引切片等。但是,numpy 在转换过程中将类似列表的对象强制转换为数组

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'>

这意味着我丢失了对象以及与之关联的其他数据和方法

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

我如何得到这个结果?

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

如果我也能像这样控制强制的深度就更好了

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)
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)

元素 methods/attributes 必须通过列表理解来访问,就像列表一样:

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 也可以用于此,但时间大致相同:

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

我认为你希望实现这个:

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

但是你不能从 builtin_function.. subclass,尽管你可以尝试从 np.ndarray

相反,我设法写了

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__()

测试:

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")

注1

只要您不为 LikeList class 实现 __len__ 方法,此方法就有效。

注2

如果您坚持,请将某种巫术附加到这一行。

  1. 空项目如:'',None, []
  2. 另一个暗淡的实例为:LikeList([7])
  3. 另一个对象为:5,...(省略号),'hello',0.1

(我想不通,为什么 np.array 没有检测到 dtype=object)