探索 NumPy 数组的重塑技巧
本教程将深入讲解如何运用 NumPy 的 reshape()
函数来调整 NumPy 数组的结构,而无需触及原始数据。
在处理 NumPy 数组时,你可能经常需要将现有的数组转换为具有不同维度的形式。 当你在数据处理过程中执行多个步骤时,这个需求尤其突出。
NumPy reshape()
提供了一种简洁的方法来实现这一目标。 在接下来的内容中,你将掌握 reshape()
的使用方法,并学会将数组转换成各种维度。
理解 NumPy 数组的重塑
在 NumPy 数组的运用中,你可能会先创建一个一维的数字数组。 之后,你需要将其转化为符合需求的特定维度数组。
当新数组的维度在初始阶段未知或需要在运算过程中推导时,这种重塑操作显得尤为重要。 此外,某些特定的数据处理步骤也可能需要输入具有特定形状的数据。
这时,重塑就派上了用场。
举个例子,想象一下一个由 6 个元素组成的一维数组,我们称之为向量。 我们可以将其重塑为 2×3、3×2 或 6×1 等不同形状的数组。
▶️ 为了更好地理解本教程中的示例,请确保你的环境中已经安装了 Python 和 NumPy。 如果你还没有安装 NumPy,请参考我们的 NumPy 安装指南。
现在,你可以通过运行 import numpy as np
来导入 NumPy 并将其命名为 np
,以便在后续代码中使用。
接下来,我们将深入探讨 reshape()
的语法。
NumPy reshape()
的语法
以下是 NumPy reshape()
函数的基本语法:
np.reshape(arr, newshape, order="C"|"F"|"A")
arr
:这是一个有效的 NumPy 数组对象,也就是你需要进行重塑的数组。newshape
:这是新数组的形状。 它可以是一个整数或一个元组。- 当
newshape
是一个整数时,返回的数组将是一维的。 order
:这个参数定义了读取需要重塑的数组元素的顺序。- 默认值是
'C'
,意味着数组元素将按照类似 C 的索引顺序(从 0 开始)读取。 'F'
代表类似 Fortran 的索引顺序(从 1 开始)。 而'A'
则根据数组arr
的内存布局,选择类似 C 或类似 Fortran 的顺序读取元素。
那么 np.reshape()
会返回什么呢?
它会尽可能返回原始数组的重塑视图。 如果无法返回视图,它会返回数组的一个副本。
上面提到,NumPy 的 reshape()
函数会尽量返回视图。 接下来,我们将深入探讨视图和副本之间的差异。
NumPy 数组的视图与副本
顾名思义,副本是原始数组的一个独立复制版本。 对副本的任何修改都不会影响到原始数组。
而视图,则是原始数组的一种重塑形式。 这意味着对视图的任何修改都会直接反映到原始数组,反之亦然。
运用 NumPy reshape()
将一维数组转化为二维数组
#1. 首先,我们使用 np.arange()
创建一个示例数组。
我们需要一个包含 1 到 12 共 12 个数字的数组,我们称之为 arr1
。 由于 NumPy 的 arange()
函数默认不包含结束值,所以我们将结束值设置为 13。
现在,让我们运用上面的语法,将 arr1
重塑为一个形状为 (4, 3) 的二维数组。 我们将这个数组命名为 arr2
,它将包含 4 行和 3 列。
import numpy as np
arr1 = np.arange(1,13)
print("原始数组,重塑前:\n")
print(arr1)
# 重塑数组
arr2 = np.reshape(arr1,(4,3))
print("\n重塑后的数组:")
print(arr2)
让我们看看原始数组和重塑后的数组。
原始数组,重塑前:
[ 1 2 3 4 5 6 7 8 9 10 11 12]
重塑后的数组:
[[ 1 2 3]
[ 4 5 6]
[ 7 8 9]
[10 11 12]]
除了将数组作为参数传递给 np.reshape()
,你还可以在原始数组上直接调用 .reshape()
方法。
你可以运行 dir(arr1)
来查看数组对象 arr1
可用的所有方法和属性。
dir(arr1)
# 输出
[
...
...
'reshape'
...
..
]
从上面的代码单元中,你可以看到 .reshape()
是一个可以应用到现有 NumPy 数组 arr1
上的有效方法。
▶️ 因此,你也可以使用以下更简洁的语法来重塑 NumPy 数组。
arr.reshape(d0,d1,...,dn)
# 其中:
# d0, d1,..,dn 是重塑后数组的维度
# d0 * d1 * ...* dn = N,arr 中的元素总数
在接下来的教程中,我们将使用这种更简洁的语法来演示。
#2. 让我们尝试将我们的 12 元素向量重塑为一个 12 x 1 的数组。
import numpy as np
arr1 = np.arange(1,13)
print("原始数组,重塑前:\n")
print(arr1)
# 重塑数组
arr3 = arr1.reshape(12,1)
print("\n重塑后的数组:")
print(arr3)
在下面的输出中,你可以看到数组已成功重塑。
原始数组,重塑前:
[ 1 2 3 4 5 6 7 8 9 10 11 12]
重塑后的数组:
[[ 1]
[ 2]
[ 3]
[ 4]
[ 5]
[ 6]
[ 7]
[ 8]
[ 9]
[10]
[11]
[12]]
❔ 那么,我们如何确定得到的是副本还是视图呢?
你可以调用返回数组的基本属性来检查。
- 如果数组是副本,那么基本属性将返回
None
。 - 如果数组是视图,那么基本属性将返回原始数组。
让我们快速验证一下。
arr3.base
# 输出
array([ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])
正如你所看到的,arr3
的 base
属性返回了原始数组。 这意味着我们得到的是原始数组的视图。
#3. 现在,让我们尝试将向量重塑为另一个有效的 2 x 6 数组。
import numpy as np
arr1 = np.arange(1,13)
print("原始数组,重塑前:\n")
print(arr1)
# 重塑数组
arr4 = arr1.reshape(2,6)
print("\n重塑后的数组:")
print(arr4)
这是输出:
原始数组,重塑前:
[ 1 2 3 4 5 6 7 8 9 10 11 12]
重塑后的数组:
[[ 1 2 3 4 5 6]
[ 7 8 9 10 11 12]]
在下一节中,我们将把 arr1
重塑为一个三维数组。
运用 NumPy reshape()
将一维数组转化为三维数组
要将 arr1
重塑为一个三维数组,我们将所需的维度设置为 (1, 4, 3)。
import numpy as np
arr1 = np.arange(1,13)
print("原始数组,重塑前:\n")
print(arr1)
# 重塑数组
arr3D = arr1.reshape(1,4,3)
print("\n重塑后的数组:")
print(arr3D)
我们现在已经创建了一个与原始数组 arr1
包含相同 12 个元素的三维数组。
原始数组,重塑前:
[ 1 2 3 4 5 6 7 8 9 10 11 12]
重塑后的数组:
[[[ 1 2 3]
[ 4 5 6]
[ 7 8 9]
[10 11 12]]]
如何在重塑过程中调试值错误
如果你还记得 reshape()
的语法,那么只有当维度乘积等于数组中的元素数量时,重塑操作才有效。
import numpy as np
arr1 = np.arange(1,13)
print("原始数组,重塑前:\n")
print(arr1)
# 重塑数组
arr2D = arr1.reshape(4,4)
print("\n重塑后的数组:")
print(arr2D)
在这里,我们尝试将一个包含 12 个元素的数组重塑为一个 4×4 的数组,而后者应该包含 16 个元素。 因此,解释器会抛出一个值错误,如下所示。
原始数组,重塑前:
[ 1 2 3 4 5 6 7 8 9 10 11 12]
-----------------------------------------------------------
ValueError
Traceback (most recent call last)
<ipython-input-11-63552bcc8c37> in <module>()
6
7 # 重塑数组
----> 8 arr2 = arr1.reshape(4,4)
9 print("\n重塑后的数组:")
10 print(arr2)
ValueError: cannot reshape array of size 12 into shape (4,4)
为了避免此类错误,你可以使用 -1
来自动推断其中一个维度的形状,使其与元素总数相匹配。
例如,如果你事先知道 n-1 个维度,你可以使用 -1
来推断重塑数组中的第 n 个维度。
假设你有一个包含 24 个元素的数组,并且你想将其重塑为一个三维数组。 你需要 4 行和 3 列,你可以沿着第三个维度传入 -1
的值。
import numpy as np
arr1 = np.arange(1,25)
print("原始数组,重塑前:\n")
print(arr1)
# 重塑数组
arr_res = arr1.reshape(4,3,-1)
print("\n重塑后的数组:")
print(arr_res)
print(f"arr_res 的形状:{arr_res.shape}")
当你检查形状数组的形状时,你会发现重塑后的数组在第三维的形状为 2。
原始数组,重塑前:
[ 1 2 3 4 5 6 7 8 9 10 11 12
13 14 15 16 17 18 19 20 21 22 23 24]
重塑后的数组:
[[[ 1 2]
[ 3 4]
[ 5 6]]
[[ 7 8]
[ 9 10]
[11 12]]
[[13 14]
[15 16]
[17 18]]
[[19 20]
[21 22]
[23 24]]]
arr_res 的形状:(4, 3, 2)
这种方法在扁平化数组时尤其有用,我们将在下一节中讨论。
运用 NumPy reshape()
扁平化数组
有时,你可能需要从一个 N 维数组返回到一个扁平数组。 例如,你可能需要将一个图像扁平化为一个长像素向量。
让我们使用以下步骤创建一个简单的示例:
- 生成一个 3×3 的灰度图像数组
img_arr
,像素值范围为 0 到 255。 - 接下来,扁平化
img_arr
并打印扁平化后的数组flat_arr
。 - 此外,打印
img_arr
和flat_arr
的形状以进行验证。
img_arr = np.random.randint(0, 255, (3,3))
print(img_arr)
print(f"img_arr 的形状: {img_arr.shape}")
flat_arr = img_arr.reshape(-1)
print(flat_arr)
print(f"flat_arr 的形状: {flat_arr.shape}")
以下是输出结果。
[[195 145 77]
[ 63 193 223]
[215 43 36]]
img_arr 的形状: (3, 3)
[195 145 77 63 193 223 215 43 36]
flat_arr 的形状: (9,)
在上面的代码单元中,你可以看到 flat_arr
是一个包含 9 个像素值的一维向量。
总结👩🏫
是时候快速回顾一下我们所学的内容了。
- 使用
np.reshape(arr, newshape)
将arr
重塑为newshape
中指定的形状。newshape
是一个元组,指定了重塑后数组的维度。 - 或者,使用
arr.reshape(d0, d1, ..., dn)
将arr
重塑为形状d0 x d1 x ... x dn
。 - 请务必检查
d0 * d1 * ...* dn = N
,其中N
是原始数组中的元素数量,以避免重塑过程中的值错误。 - 如果你想自动推断维度,可以在新形状中最多使用一个维度设置为
-1
。 - 最后,你可以使用
arr.reshape(-1)
来扁平化数组。
现在你已经掌握了如何使用 NumPy 的 reshape()
函数,接下来可以深入了解 NumPy 的 linspace()
函数的工作原理。
如果你愿意,可以在 Jupyter notebook 中尝试这些代码示例。 如果你在寻找其他开发环境,可以参考我们的 Jupyter 替代品指南。