了解类似的numpy展平技术之间的差异

时间:2019-03-31 07:58:34

标签: python image numpy reshape

我正在研究Coursera上的deeplearning.ai证书中第一门课程第二周的作业。

首要任务之一是展平图像(209、64、64、3)。您可以通过三种方式(或我认为)执行此操作:

  1. X.reshape(X.shape [0],-1).T
  2. X.flatten()。reshape(12288,209)
  3. X.reshape(12288,209)

在此练习中,我发现只有选项一可以正确重塑图像,但我不知道为什么。任何帮助将非常感激。

3 个答案:

答案 0 :(得分:2)

首先,我们注意到我们可以认为reshape是将数组“拉出”到一长串元素中,然后通过以一定顺序填充轴来“重新堆叠”它们。考虑以下数组:

array = np.arange(48).reshape(6, 4, 2)

此数组将包含0到47之间的元素,形状为(6, 4, 2)。这种形状可以简单地解释为将元素放置在每个轴中的顺序

例如:

>>> print(array[0, :, :])
[[0 1]
 [2 3]
 [4 5]
 [6 7]]

第一轴的长度为48 / 4 / 2 = 8,因此此切片必须包含8个元素。由于它是 first 轴,因此按运行顺序仅由源的前8个元素组成。

接下来,我们需要确定这8个元素将如何填充其他2个轴。可以认为这8个元素构成了它们自己的子数组,形状为(4, 2)。由于必须先填充第一个轴(在子数组中),因此我们希望它包含按运行顺序排列的成对元素:

>>> for i in range(array.shape[1]):
...    print(array[0, i, :])
[0 1]
[2 3]
[4 5]
[6 7]

将此与最后一个轴进行对比:

>>> for i in range(array.shape[2]):
...     print(array[0, :, i])
[0 2 4 6]
[1 3 5 7]

第二个切片array[1, :, :]将包含 next 8个元素(即8到15),并重复此过程,直到不再剩余元素为止。

现在,请注意,“拉出”步骤类似于flatten()。因此,毫不奇怪的是2和3 相同

X = np.random.rand(209, 64, 64, 3)
print(X.flatten().reshape(12288, 209) == X.reshape(12288, 209)).all(axis=None)

输出:

True

粗略地与1.比较将显示1.因此是奇数。请注意,X.shape[0]等于209X第一轴的长度)。因此,1.等效于X.reshape(209, -1).T(-1是推断最后一个轴的简写,而.T则转置数组)。

因此,两者的不同之处不在于它们的形状,而是元素放置在轴中的顺序。 2.和3.从同一点开始,由第一行中的元素组成的扁平数组,然后是第二行,然后是第三行,依此类推。因此,(0, 0)包含第一个原始元素,然后包含(0, 1)(0, 2) ...

另一方面,通过在1.中进行重塑和 then 转置,不再遵循元素的线性顺序。而是先填充列,以使(0, 0)包含第一个原始元素,然后包含(1, 0),依此类推。

答案 1 :(得分:0)

所有三个操作的最终结果将相同。这三种方法只是获得相同结果的三种不同方法。但是应该有一些收获,对不对?就在这里。

  1. X.reshape(X.shape [0],-1).T :当您将-1作为轴传递给整形操作时,您说的是{{1} }。因为Hey, here is my array. I am giving you the first dimension(X.shape[0] in this case), figure out yourself what the second dimesnion should be!只是元素排列的另一种方式,所以reshape将采用所有其他维度,并采用第二维度的形状乘积。
  2. X.flatten()。reshape(12288,209):在这里,您说的是numpy,而不是直接重塑它,而是先将其Yes, I know the shape of the ndarray I want移出并然后重新排列元素。
  3. X.reshape(12288,209):这与第二个选项相同,但是知道您没有执行 flattened redundant重塑ndarray的操作。

还有什么?:花费时间

flatten

答案 2 :(得分:0)

(209, 64, 64, 3)看起来像图像阵列的形状,每个图像209个(64、64、3)。重塑应将这些图像元素保持在一起且有序。

以一个较小的示例为例:

In [845]: arr = np.arange(24).reshape(4,2,3)                                    
In [846]: arr                                                                   
Out[846]: 
array([[[ 0,  1,  2],
        [ 3,  4,  5]],

       [[ 6,  7,  8],
        [ 9, 10, 11]],

       [[12, 13, 14],
        [15, 16, 17]],

       [[18, 19, 20],
        [21, 22, 23]]])
In [847]: arr[1]                                                                
Out[847]: 
array([[ 6,  7,  8],
       [ 9, 10, 11]])

天真重塑:

In [848]: x = arr.reshape(6,4)                                                  
In [849]: x                                                                     
Out[849]: 
array([[ 0,  1,  2,  3],
       [ 4,  5,  6,  7],
       [ 8,  9, 10, 11],
       [12, 13, 14, 15],
       [16, 17, 18, 19],
       [20, 21, 22, 23]])
In [850]: x[:,1]                                                                
Out[850]: array([ 1,  5,  9, 13, 17, 21])

选择一列将产生与Out[847]中不同的数字集。 [6,7,8]现在在第2行和第3行之间进行划分。[1,5,9...]arr的各处绘制。

重塑然后转置:(4,2,3)=>(4,(2 * 3))=>(4,6)=>(6,4):

In [851]: x = arr.reshape(4,6).T                                                
In [852]: x                                                                     
Out[852]: 
array([[ 0,  6, 12, 18],
       [ 1,  7, 13, 19],
       [ 2,  8, 14, 20],
       [ 3,  9, 15, 21],
       [ 4, 10, 16, 22],
       [ 5, 11, 17, 23]])
In [853]: x[:,1]                                                                
Out[853]: array([ 6,  7,  8,  9, 10, 11])
In [855]: x[:,1].reshape(2,3)                                                   
Out[855]: 
array([[ 6,  7,  8],
       [ 9, 10, 11]])

正式reshape仅要求元素总数不变。但如此处所示,维度子组也应保持相同,(4,2,3) => (4,6)(8,3),而不是(6,4)。否则,您可能会有重新组合值的风险。

仅进行整形和转置,x仍然是view,与arr共享数据缓冲区。但是order是不同的。进一步重塑(例如ravel)可能会产生副本。

In [859]: arr.__array_interface__['data']                                       
Out[859]: (36072624, False)
In [860]: x.__array_interface__['data']                                         
Out[860]: (36072624, False)
In [861]: x.ravel()                                                             
Out[861]: 
array([ 0,  6, 12, 18,  1,  7,...])
In [862]: x.ravel(order='F')                                                    
Out[862]: 
array([ 0,  1,  2,  3,  4,  5, ...])