numpy:停止 numpy.array() 尝试协调元素。从列表创建 ndarray 而不尝试合并/协调元素

numpy: Stop numpy.array() from trying to reconcile elements. Create ndarry from list without trying to merge / reconcile the elements

我在一个列表中有两个二维矩阵,我想将其转换为一个 numpy 数组。下面是 3 个示例 a,b,c .

>>> import numpy as np
>>> a = [np.zeros((3,5)), np.zeros((2,9))]
>>> np.array(a)
>>> array([array([[0., 0., 0., 0., 0.],
    [0., 0., 0., 0., 0.],
    [0., 0., 0., 0., 0.]]),
    array([[0., 0., 0., 0., 0., 0., 0., 0., 0.],
    [0., 0., 0., 0., 0., 0., 0., 0., 0.]])], dtype=object)
>>> b = [np.zeros((3,5)), np.zeros((3,9))]
np.array(b)
Traceback (most recent call last):
  File "C:\Program Files\JetBrains\PyCharm 2019.2.4\helpers\pydev\_pydevd_bundle\pydevd_exec.py", line 3, in Exec
    exec exp in global_vars, local_vars
  File "<input>", line 1, in <module>
ValueError: could not broadcast input array from shape (3,5) into shape (3)
>>> c = [np.zeros((3,5)), np.zeros((4,9))]
np.array(c)
array([array([[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0.]]),
array([[0., 0., 0., 0., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0., 0., 0., 0.],
[0., 0., 0., 0., 0., 0., 0., 0., 0.]])], dtype=object)

可以观察到案例 a & c 有效,但 b 无效。 b 确实抛出异常。不同之处在于,在示例 b 中,2 个矩阵的第一个维度匹配。

我发现了以下 ,它解释了为什么会出现这种情况。

If only the first dimension does not match, the arrays are still matched, but as individual objects, no attempt is made to reconcile them into a new (four dimensional) array.

我的问题:我不想让 numpy 协调矩阵。我只想要与第一个维度不匹配时相同的行为。我希望它们 作为独立对象进行匹配,即使 它们具有 相同的第一个维度 。我该如何实现?

即使您明确将 object 作为数据类型传递,Numpy 仍然会报错:

>>> np.array(b, dtype=object)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ValueError: could not broadcast input array from shape (3,5) into shape (3)

本质上,numpy 并不是真正围绕使用 dtype=object 编写的,它总是假定您想要一个具有原始数字或结构化 dtype 的数组。

所以我认为你唯一的选择是:

>>> arr = np.empty(len(b), dtype=object)
>>> arr[:] = b
>>> arr
array([array([[0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0.]]),
       array([[0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0.]])], dtype=object)

为了好玩,您可以使用实际的 np.ndarray 类型构造函数,尽管这不是很容易:

>>> np.ndarray(dtype=object, shape=len(b), buffer=np.array(list(map(id, b)),dtype=np.uint64))
array([array([[0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0.]]),
       array([[0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0.]])], dtype=object)

请注意,这依赖于 CPython 实现细节,id 只是 python 对象的地址。所以大多数时候我只是为了好玩而展示它。

在最新版本中我们开始看到警告:

In [185]: np.__version__                                                                             
Out[185]: '1.19.0'
                                                
In [187]: np.array([np.zeros((3,5)), np.zeros((2,9))])                                               
/usr/local/bin/ipython3:1: VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify 'dtype=object' when creating the ndarray
  #!/usr/bin/python3
Out[187]: 
array([array([[0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0.]]),
       array([[0., 0., 0., 0., 0., 0., 0., 0., 0.],
       [0., 0., 0., 0., 0., 0., 0., 0., 0.]])], dtype=object)

它仍然使对象成为 dtype 数组。在匹配的第一维情况下,我们收到警告和错误。

In [188]: np.array([np.zeros((3,5)), np.zeros((3,9))])                                               
/usr/local/bin/ipython3:1: VisibleDeprecationWarning: Creating an ndarray from ragged nested sequences (which is a list-or-tuple of lists-or-tuples-or ndarrays with different lengths or shapes) is deprecated. If you meant to do this, you must specify 'dtype=object' when creating the ndarray
  #!/usr/bin/python3
---------------------------------------------------------------------------
ValueError                                Traceback (most recent call last)
<ipython-input-188-b6a4475774d0> in <module>
----> 1 np.array([np.zeros((3,5)), np.zeros((3,9))])

ValueError: could not broadcast input array from shape (3,5) into shape (3)

基本上 np.array 作为第一步尝试创建一个多维数值数组。失败它需要两条路线 - 创建一个对象 dtype 数组或失败。细节隐藏在编译代码中。

如果您想完全控制对象数组的创建方式,预分配和赋值是最好的方法。

In [189]: res=np.empty(2,object)                                                                     
In [191]: res[:] = [np.zeros((3,5)), np.zeros((3,9))]