Numpy重塑 - 如何重塑数组以及-1是什么意思?

199 阅读11分钟

如何重塑一个numpy数组?

numpy.reshape() 函数被用来重塑一个numpy数组,而不改变数组中的数据。重塑数组以使其与进一步的计算兼容是一种非常普遍的做法。

在这篇文章中,你将了解到numpy.reshape 函数的可能使用情况。

numpy.reshape

  • 语法: numpy.reshape(a, newshape, order='C')
  • 目的: 在不改变数据的情况下给数组赋予 一个新的形状。
  • 参数:
    • a: 要重塑的类似数组的数组
    • newshape: int或ints的tuples应与原始形状兼容。如果是整数,那么结果将是一个该长度的一维数组。一个形状的维度可以是-1.在这种情况下,值是由数组的长度和其余维度推断出来的。
    • order: {'C', 'F', 'A'}, 可选使用该索引顺序读取a的元素,并使用该索引顺序将元素放入重塑的数组中。详细的用法将进一步讨论。
  • 返回reshaped_arrayndarray
# Import Packages
import numpy as np

1.Numpy.reshape函数

numpy.reshape() 函数用于改变numpy数组的形状而不修改数组数据。要使用这个函数,请将数组和新的形状传递给np.reshape() 。 shape参数应该以 "tuple "或 "int "的形式传递。

让我们通过例子来了解一下。

将一维数组重塑为二维数组

在这个例子中,你必须将一个形状为(8,)的一维数组转换成形状为(4,2)的二维数组。

第1步:创建一个形状为(8,)的numpy数组

num_array = np.array([1,2,3,4,5,6,7,8])
num_array
array([1, 2, 3, 4, 5, 6, 7, 8])

第2步:使用np.reshape() ,新的形状为(4,2)

np.reshape(num_array, (4,2))
array([[1, 2],
       [3, 4],
       [5, 6],
       [7, 8]])

正如你所看到的,输入数组的形状已经被改变为(4,2)。这是一个二维数组,包含原始输入的一维数组中的相同数据。

将2-D数组重塑为3-D数组

在这个例子中,你必须将一个形状为(4,2)的二维数组转换为形状为(2,2,2)的三维数组。

步骤1:创建一个形状为(4,2)的numpy数组

num_array = np.array([[1, 2],
                      [3, 4],
                      [5, 6],
                      [7, 8]])

num_array
array([[1, 2],
       [3, 4],
       [5, 6],
       [7, 8]])

第2步:使用np.reshape() 函数,新的形状为(2, 2, 2)

np.reshape(num_array, (2,2,2))
array([[[1, 2],
        [3, 4]],

       [[5, 6],
        [7, 8]]])

正如你所看到的,输入数组的形状已经被改变为(2,2,2)。这是一个3-D数组,包含了原始输入2-D数组中的相同数据。

2.你能把numpy数组重塑成任何形状吗?

np.reshape() 函数返回转换后的数组,并在函数中提供新的形状。唯一的条件是原始数组中的元素数和转换后的数组中的元素数应该相等。

如果你不知道如何找出数组中的元素数,只需将每个轴/维的元素数相乘。它只是意味着形状元组中提到的所有数字的乘法。

让我们看看如果你试图重塑一个不等元素的数组会发生什么

第1步:创建一个形状为(5,)的numpy数组

a = np.array([1,2,3,4,5])
a
array([1, 2, 3, 4, 5])

第2步:使用np.reshape() ,新的形状为(2,5)

np.reshape(a, (2,5))   

#> Throws ValueError

在这种情况下,会产生一个ValueError 异常。这里的问题是,原始数组有5个元素。但是新的形状,定义为(2,5) ,希望有2×5=10个元素。元素的数量不匹配,因此,代码失败。

但是,如果你想重塑一个未知维度的形状呢?

你可以用-1来表示未知维度。

3.numpy.reshape中的-1是什么意思?

np.reshape() 函数支持对未知维度或占位符的强大使用(-1)

当定义一个新的形状时,你可以把其中一个维度作为未知数。Numpy将自动推断出适合该特定形状的尺寸。这是为了确保输入和输出数组有相同数量的元素。

当输入数组的确切尺寸不知道,但一些输出尺寸是已知的时候,它可能会很有用。让我们看一个例子,输入数组的尺寸不知道,但输出数组中需要有2行。

步骤1:创建一个numpy数组

num_array = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
num_array
array([[[1, 2],
        [3, 4]],

       [[5, 6],
        [7, 8]]])

第2步:使用np.reshape() 函数,新的形状为(2,-1)

np.reshape(num_array, (2,-1))
array([[1, 2, 3, 4],
       [5, 6, 7, 8]])

给定的输入数组是一个形状为(2,2,2)的3-D数组。

那么(2, -1)中的-1是什么意思?

这个-1通知numpy自动推断该轴的尺寸。(2,-1)因此,在对形状np.reshape() ,Numpy能够自动推断出最后一个维度为4。

但是如果你不在输出数组的维度中加入1,而只是简单地使用-1,会发生什么?

4.扁平化数组

这是使用未知维度重塑numpy数组的一个扩展用例。未知尺寸占位符(-1) ,允许numpy自动推断出尺寸。这个技巧可以用来扁平化一个数组。如果(-1) 占位符被放置在np.reshape() 函数中,那么该函数就会返回一个扁平化的数组。

让我们看看下面的一个例子。

步骤1:创建一个3-D的numpy数组

a_3d_array = np.array([[[1, 2], [3, 4]], [[5, 6], [7, 8]]])
a_3d_array
array([[[1, 2],
        [3, 4]],

       [[5, 6],
        [7, 8]]])

第2步:使用np.reshape() 函数,新的形状为(-1)

np.reshape(a_3d_array, (-1))
array([1, 2, 3, 4, 5, 6, 7, 8])

在这里,一个形状为(2,2,2) 的三维数组被扁平化为一个一维数组。

5.如何改变numpy reshape过程的顺序?

在一个抽象的层面上,np.reshape() 函数的工作方式是这样的,它从一个解卷或扁平化过程开始。这时,输入数组的所有元素都被压扁成一个一维数组,然后根据提供的输入形状进行回滚或重塑。但是numpy如何决定哪个维度的元素会先被压平,以及元素会以何种顺序被放回?而如果你希望改变这个顺序呢?

这个展开的顺序可以通过np.reshape() 函数中的order 参数来控制。这个参数可以取3个值:

  • C:C-like顺序索引
  • F:类似Fortran的顺序索引
  • A:要么按C的顺序,要么按Fortran的顺序

让我们来讨论一下它们各自的情况。

类C顺序索引

这里的C代表C语言,这种顺序被称为类C顺序索引。根据这个顺序,数组的最后一个索引或维度变化最快,第一个索引变化最慢。

简单的说,解卷从最后一个维度的元素开始,然后向第一个维度的元素进行。在创建输出数组时,回滚过程中也会保持这种排序。这也是np.reshape() 函数中的默认值。

让我们看看下面的例子。

第1步:创建一个二维numpy数组

对于这种情况,让我们创建一个特殊的数组。这个二维数组的元素将对应于各自的行号和列号。例如,元素 "R1C2 "代表第一行和第二列的元素。

a_2d_array = np.array([['R1C1', 'R1C2'], ['R2C1', 'R2C2'], ['R3C1', 'R3C2']])
a_2d_array
array([['R1C1', 'R1C2'],
       ['R2C1', 'R2C2'],
       ['R3C1', 'R3C2']], dtype='<U4')

第2步:使用np.reshape() ,将新的形状作为(2,3) 和顺序C

np.reshape(a_2d_array, (2,3), order='C')
array([['R1C1', 'R1C2', 'R2C1'],
       ['R2C2', 'R3C1', 'R3C2']], dtype='<U4')

上面的输出清楚地表明,在输入的二维数组的最后一维中,列首先被压平。这些元素按照 "R1C1"、"R1C2"、"R2C1 "的顺序被压扁,依次类推。然后在重塑过程中,"R1C1 "被放在第一行第一列,"R1C2 "被放在第一行第二列,而 "R2C1 "被放在第一行第三列。

"R2C1 "的放置方式是为了使输出数组的形状与输入数组的形状兼容。

类似于Fortran的顺序索引

F在这里代表了Fortran语言。这里,第一个索引或维度变化最快,后面的索引变化最慢。换句话说,解卷过程从第一个维度开始,然后向最后一个维度进行。这个顺序在回滚过程中也会保持。

让我们看看下面的例子。

第1步:创建一个2维的numpy数组

# Using the same array created in 'C' order

a_2d_array
array([['R1C1', 'R1C2'],
       ['R2C1', 'R2C2'],
       ['R3C1', 'R3C2']], dtype='<U4')

第2步:使用np.reshape() 函数,将新的形状作为(2,3) 和顺序F

np.reshape(a_2d_array, (2,3), order='F')
array([['R1C1', 'R3C1', 'R2C2'],
       ['R2C1', 'R1C2', 'R3C2']], dtype='<U4')

上面的输出描述了在输入的2-D数组的第一维中,行首先被压平了。这些元素按照 "R1C1"、"R2C1"、"R3C1 "的顺序被压扁,以此类推。然后在重塑过程中,"R1C1 "被放置在第一行第一列,"R2C1 "被放置在第二行第一列,"R3C1 "被放置在第一行第二列。

"R3C1 "以这样的方式被放置,使输出阵列的形状与输入阵列的形状兼容。

A订单

这种类型的顺序没有任何具体规则。它取决于阵列在内存中的存储方式。如果数组被存储在类似C语言的存储器中,那么就使用C 顺序,如果数组被存储为类似Fortran的存储器,那么就使用F 顺序。用户并不知道输出的结果是什么,这就是为什么这种排序很少被使用。

6.重塑数组的其他方法

虽然,一个numpy数组可以使用np.reshape() 函数来重塑,但是,还有一些其他的方法。两个这样的方法是。

  • Numpy数组对象函数
  • 使用np.ravel() ,结合使用np.reshape()

让我们探讨一下这些方法。

用于重塑数组的Numpy数组对象函数

numpy数组对象支持几乎所有可以使用numpy显式函数进行的操作。通过访问numpy数组对象的.reshape() 函数,可以对numpy数组进行重塑。请看下面的例子。

步骤1:创建一个形状为(8,)的numpy数组

num_array = np.array([1,2,3,4,5,6,7,8])
num_array
array([1, 2, 3, 4, 5, 6, 7, 8])

第2步:从numpy数组对象中使用.reshape() 函数,新的形状为(4,2)

num_array.reshape((4,2))
array([[1, 2],
       [3, 4],
       [5, 6],
       [7, 8]])

使用np.ravel()与np.reshape()组合来重塑数组

np.ravel() 函数用于扁平化numpy数组。它将多维数组作为一个扁平化的连续数组返回。这个函数可以和 函数结合使用。ravel函数的结果可以在定义了新的形状后传入reshape函数,它仍然会返回正确的结果。np.reshape()

让我们看一个例子。

第1步:创建一个形状为(8,)的numpy数组

num_array = np.array([1,2,3,4,5,6,7,8])
num_array
array([1, 2, 3, 4, 5, 6, 7, 8])

第2步:使用np.reshape()np.ravel() 函数,新形状为(4,2)

np.reshape(np.ravel(num_array), (4,2))
array([[1, 2],
       [3, 4],
       [5, 6],
       [7, 8]])

7.高级重塑

如上节所述,重塑numpy数组的另一种方法是使用np.ravel() 函数平铺数组。然后将ravel函数的输出和新的形状一起作为np.reshape() 函数的输入,作为最终的输出数组。

np.ravel() 浏览器也支持 参数,其工作方式与 函数相同。因此,人们可以有不同的扁平化和重塑的顺序。让我们来讨论这些情况。order np.reshape()

案例1:按C顺序扁平化,按F顺序重塑

在这种情况下,使用np.ravel() 函数和order 参数C 对数组进行扁平化。对于np.reshape() 函数,顺序参数将是F

步骤1:创建一个形状为(8,)的numpy数组

num_array = np.array([1,2,3,4,5,6,7,8])
num_array
array([1, 2, 3, 4, 5, 6, 7, 8])

第2步:使用np.reshape()np.ravel() 函数,新的形状为(4,2)

np.reshape(np.ravel(num_array, order='C'), (4,2), order='F')
array([[1, 5],
       [2, 6],
       [3, 7],
       [4, 8]])

案例2:按F顺序扁平化,按C顺序重塑

在这种情况下,使用np.ravel() 函数和order 参数F 对数组进行扁平化处理。对于np.reshape() 函数,顺序参数将是C

步骤1:创建一个形状为(8,)的numpy数组

num_array = np.array([1,2,3,4,5,6,7,8])
num_array
array([1, 2, 3, 4, 5, 6, 7, 8])

第2步:使用np.reshape()np.ravel() 函数,新的形状为(4,2)

np.reshape(np.ravel(num_array, order='F'), (4,2), order='C')
array([[1, 2],
       [3, 4],
       [5, 6],
       [7, 8]])

8.测试你的知识

Q1: 如果在shape tuple中传递了一个负的索引怎么办? (假设只有一个负的索引)

解答:numpy会自动推断出一个负数。 numpy会自动推断出-1是一个缺失的维度,并自行选择正确的维度。

问2:"C "和 "F "顺序的区别是什么?

解答:在 "C "顺序中,最后一个维度是 "F"。 在'C'顺序中,数组的最后一个索引或维度变化最快,而第一个索引变化最慢。但是在'F'顺序中,第一个索引或维度的变化最快,而后面的索引变化最慢。

Q3: 列举两种扁平化numpy数组的方法。

答案是

  1. 使用np.ravel() 函数

  2. np.shape() 函数中使用未知维度占位符-1