了解 ndarray 形状

Understanding ndarray shapes

我是 numpy 的新手,无法理解数组的形状是如何决定的。

形式的数组
[[[5, 10, 15], [20, 25, 30], [35, 40, 45]], [1,2,4,3]] 

的形状为 (2,) 而其中一种形式为

[[[5, 10, 15], [20, 25, 30], [35, 40, 45]], [1,2,4]] 

的形状为 (2,3)。此外,

[[[5, 10, 15], [20, 25, 30], [35, 40, 45]], [[1,2,4], [3,4,2]]] 

具有 (2,) 的形状,但添加另一个向量作为

[[[5, 10, 15], [20, 25, 30], [35, 40, 45]], [[1,2,4], [3,4,2], [1,2,4]]] 

将形状更改为 (2,3,3)。直觉上,我觉得所有的数组都应该是3维的。谁能帮助我了解到底发生了什么?

基本思想是 np.array 尝试创建尽可能高的维度数组。当子列表具有匹配数量的元素时,结果很容易看到。当他们混合使用不同长度的列表时,结果可能会令人困惑。

在您的第一种情况下,您有 2 个子列表,一个长度为 3,另一个长度为 4。因此它构成了一个 2 元素对象数组,并且不会尝试解析第一个子列表的子列表

In [1]: arr = np.array([[[5, 10, 15], [20, 25, 30], [35, 40, 45]], [1,2,4,3]])
In [2]: arr
Out[2]: array([[[5, 10, 15], [20, 25, 30], [35, 40, 45]], 
               [1, 2, 4, 3]
              ], dtype=object)   # adjusted format
In [3]: arr.dtype
Out[3]: dtype('O')
In [4]: arr.shape
Out[4]: (2,)
In [5]: arr[0]
Out[5]: [[5, 10, 15], [20, 25, 30], [35, 40, 45]] # 3 element list of lists
In [6]: arr[1]
Out[6]: [1, 2, 4, 3]  # 4 element list of numbers

在第二种情况下,您有两个子列表,长度均为 3。因此它构成了一个 2x3 数组。但是一个子列表包含列表,其他的数字 - 所以结果又是对象数组:

In [7]: arr = np.array([[[5, 10, 15], [20, 25, 30], [35, 40, 45]], [1,2,4]] )
In [8]: arr
Out[8]: 
array([[[5, 10, 15], [20, 25, 30], [35, 40, 45]],
       [1, 2, 4]
      ], dtype=object)
In [9]: arr.shape
Out[9]: (2, 3)
In [10]: arr[0,0]
Out[10]: [5, 10, 15]

最后,2 个列表,每个列表有 3 个元素,每个列表也是 3 个元素列表 - 一个 3d 数组。

In [11]: arr = np.array([[[5, 10, 15], [20, 25, 30], [35, 40, 45]], [[1,2,4], [3,4,2], [1,2,4]]] )
In [12]: arr
Out[12]: 
array([[[ 5, 10, 15],
        [20, 25, 30],
        [35, 40, 45]],

       [[ 1,  2,  4],
        [ 3,  4,  2],
        [ 1,  2,  4]]])
In [13]: arr.shape
Out[13]: (2, 3, 3)

子列表长度的混合也可能引发错误。

一般情况下不要随意混合不同大小和内容类型的子列表。 np.array 当给定的列表将生成一个漂亮的多维数组时,其行为最可预测。混合列表长度会导致混乱。


已更新 numpy:

In [1]: np.__version__
Out[1]: '1.13.1'
In [2]: np.array([[[5, 10, 15], [20, 25, 30], [35, 40, 45]], [1,2,4,3]])
Out[2]: array([list([[5, 10, 15], [20, 25, 30], [35, 40, 45]]), list([1, 2, 4, 3])], dtype=object)

In [3]: np.array([[[5, 10, 15], [20, 25, 30], [35, 40, 45]], [1,2,4]] )
Out[3]: 
array([[list([5, 10, 15]), list([20, 25, 30]), list([35, 40, 45])],
       [1, 2, 4]], dtype=object)

它现在标识 list 个元素

最后这个例子仍然是 (2,3) 对象数组。因此,这 6 个元素中的每一个都可以是不同的 Python 类型,例如:

In [11]: np.array([[[5, 10, 15], np.array([20, 25, 30]), (35, 40, 45)], [None,2,'astr']] )
Out[11]: 
array([[list([5, 10, 15]), array([20, 25, 30]), (35, 40, 45)],
       [None, 2, 'astr']], dtype=object)
In [12]: [type(x) for x in _.flat]
Out[12]: [list, numpy.ndarray, tuple, NoneType, int, str]