NumPy 在创建数组时非常有用。如果 numpy.array
的第一个参数有一个 __getitem__
和 __len__
方法,则使用这些方法是因为它可能是一个有效序列。
不幸的是,我想创建一个包含 dtype=object
的数组,而 NumPy 没有“帮助”。
将类分解为一个最小的例子:
import numpy as np
class Test(object):
def __init__(self, iterable):
self.data = iterable
def __getitem__(self, idx):
return self.data[idx]
def __len__(self):
return len(self.data)
def __repr__(self):
return '{}({})'.format(self.__class__.__name__, self.data)
如果“iterables”有不同的长度,一切都很好,我得到了我想要的结果:
>>> np.array([Test([1,2,3]), Test([3,2])], dtype=object)
array([Test([1, 2, 3]), Test([3, 2])], dtype=object)
但是如果它们恰好具有相同的长度,NumPy 会创建一个多维数组:
>>> np.array([Test([1,2,3]), Test([3,2,1])], dtype=object)
array([[1, 2, 3],
[3, 2, 1]], dtype=object)
不幸的是,只有一个 ndmin
参数,所以我想知道是否有办法强制执行 ndmax
或以某种方式阻止 NumPy 将自定义类解释为另一个维度(不删除 __len__
或 __getitem__
)?
最佳答案
此行为之前已经讨论过多次(例如 Override a dict with numpy support )。 np.array
尝试创建尽可能高的维度数组。模型案例是嵌套列表。如果它可以迭代并且子列表的长度相等,它将“向下钻取”。
在遇到不同长度的列表之前,它下降了 2 级:
In [250]: np.array([[[1,2],[3]],[1,2]],dtype=object)
Out[250]:
array([[[1, 2], [3]],
[1, 2]], dtype=object)
In [251]: _.shape
Out[251]: (2, 2)
没有 shape 或 ndmax 参数,它无法知道我想要它是 (2,)
还是 (2,2)
。两者都适用于 dtype。
它是经过编译的代码,因此很难准确地看出它使用了哪些测试。它尝试迭代列表和元组,但不迭代集合或字典。
创建具有给定维度的对象数组的最可靠方法是从一个空数组开始,然后填充它
In [266]: A=np.empty((2,3),object)
In [267]: A.fill([[1,'one']])
In [276]: A[:]={1,2}
In [277]: A[:]=[1,2] # broadcast error
另一种方法是从至少一个不同的元素开始(例如 None
),然后替换它。
有一个更原始的创造者,ndarray
正在成形:
In [280]: np.ndarray((2,3),dtype=object)
Out[280]:
array([[None, None, None],
[None, None, None]], dtype=object)
但这与 np.empty
基本相同(除非我给它一个缓冲区)。
这些都是软糖,但它们并不昂贵(时间方面)。
================(编辑)
https://github.com/numpy/numpy/issues/5933 , Enh: Object array creation function.
是一个增强请求。还有 https://github.com/numpy/numpy/issues/5303 意外不规则数组的错误消息令人困惑
。
开发人员的情绪似乎倾向于使用一个单独的函数来创建 dtype=object
数组,一个可以更好地控制初始维度和迭代深度的函数。他们甚至可能会加强错误检查以防止 np.array
创建“不规则”数组。
这样的函数可以检测到指定深度的常规嵌套迭代的形状,并构建一个要填充的对象类型数组。
def objarray(alist, depth=1):
shape=[]; l=alist
for _ in range(depth):
shape.append(len(l))
l = l[0]
arr = np.empty(shape, dtype=object)
arr[:]=alist
return arr
具有不同的深度:
In [528]: alist=[[Test([1,2,3])], [Test([3,2,1])]]
In [529]: objarray(alist,1)
Out[529]: array([[Test([1, 2, 3])], [Test([3, 2, 1])]], dtype=object)
In [530]: objarray(alist,2)
Out[530]:
array([[Test([1, 2, 3])],
[Test([3, 2, 1])]], dtype=object)
In [531]: objarray(alist,3)
Out[531]:
array([[[1, 2, 3]],
[[3, 2, 1]]], dtype=object)
In [532]: objarray(alist,4)
...
TypeError: object of type 'int' has no len()
关于python - 防止 numpy 创建多维数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38774922/