Python广播机制
文章目录
“广播”这一术语用于描述如何在 形状不一的数组上应用算术运算。在满足特定限制的前提下,较小的数组“广播”较大的数组,使两者形状互相兼容。
广播提供了一个向量化数组操作的机制,这样遍历就发生在C层面,而不是Python层面。广播可以避免不必要的数据复制,通常导向高效的算法实现。不过,也存在不适用广播的情形(可能导致拖慢计算过程的低效内存使用)。
规则
可广播的一对张量需满足以下规则:
- 每个张量至少有一个维度。
- 迭代维度尺寸时,从尾部的维度开始,
- 维度尺寸或者相等,
- 或者其中一个张量的维度尺寸为 1 ,
- 或者其中一个张量不存在这个维度。
示例
下面是一个具体的示例,说明如何使用广播机制进行数组操作:
import numpy as np
# 创建一个数组
a = np.array([1, 2, 3])
# 形状为 (3,)
# 创建一个标量(0维数组)
b = 5
# 使用广播机制,将标量 b 扩展为与数组 a 相同的形状
c = a + b
# 广播后,a 形状为 (3,),b 形状为 (1,),c 形状为 (3,)
# c 的值为 [6, 7, 8]
# 创建一个二维数组
d = np.array([[1, 2, 3], [4, 5, 6]])
# 形状为 (2, 3)
# 创建一个一维数组
e = np.array([1, 2, 3])
# 形状为 (3,)
# 使用广播机制,将数组 e 扩展为与数组 d 相同的形状
f = d + e
# 广播后,d 形状为 (2, 3),e 形状为 (1, 3),f 形状为 (2, 3)
# f 的值为 [[2, 4, 6], [5, 7, 9]]
在这个示例中,我们使用NumPy库演示了广播机制的用法。首先,我们创建了一个数组 a
和一个标量 b
。通过使用广播机制,将标量 b
扩展为与数组 a
相同的形状,然后进行元素级的加法操作,得到数组 c
。同样地,我们还演示了对于不同形状的数组 d
和 e
,如何使用广播机制进行元素级操作。
通过广播机制,我们可以在不进行显式循环的情况下,对不同形状的数组进行元素级的操作,使得代码更简洁、清晰,并且减少了计算的复杂性。
当进行数组的广播操作时,广播机制会按照以下规则进行:
-
如果两个数组的维度数不同,那么较少的维度会在其前面补1,使得两个数组的维度数相同。
-
如果两个数组在某个维度上的大小相等,或其中一个数组在该维度上的大小为1,那么这两个数组在该维度上是兼容的。
-
如果两个数组在某个维度上的大小都不相等,且都不为1,那么这两个数组在该维度上是不兼容的,无法进行广播。
广播机制的应用不仅局限于二进制操作(如加法、减法),还可以应用于各种元素级操作,包括加法、减法、乘法、除法、幂运算、逻辑运算等。
下面是一些更多的示例,展示了广播机制在不同情况下的应用:
import numpy as np
# 示例1:不同维度的广播
a = np.array([1, 2, 3]) # 形状为 (3,)
b = np.array([[4], [5], [6]]) # 形状为 (3, 1)
c = a + b
# 广播后,a 形状为 (3,),b 形状为 (3, 1),c 形状为 (3, 3)
# c 的值为 [[5, 6, 7], [6, 7, 8], [7, 8, 9]]
# 示例2:多维度的广播
d = np.array([[1, 2, 3], [4, 5, 6]]) # 形状为 (2, 3)
e = np.array([1, 2, 3]) # 形状为 (3,)
f = d + e
# 广播后,d 形状为 (2, 3),e 形状为 (1, 3),f 形状为 (2, 3)
# f 的值为 [[2, 4, 6], [5, 7, 9]]
# 示例3:不兼容的维度
g = np.array([1, 2, 3]) # 形状为 (3,)
h = np.array([4, 5]) # 形状为 (2,)
# 由于 g 和 h 在第一个维度上的大小不相等且都不为1,无法进行广播
# 抛出 ValueError: frames are not aligned error
在示例1中,我们展示了具有不同维度的广播操作。数组 a
的形状为 (3,)
,数组 b
的形状为 (3, 1)
。通过广播机制,将数组 a
扩展为 (3, 3)
的形状,然后进行元素级的加法操作,得到数组 c
。
示例2展示了多维度的广播操作。数组 d
的形状为 (2, 3)
,数组 e
的形状为 (3,)
。通过广播机制,将数组 e
扩展为 (1, 3)
的形状,然后进行元素级的加法操作,得到数组 f
。
在示例3中,展示了具有不兼容维度的情况。数组 g
的形状为 (3,)
,数组 h
的形状为 (2,)
。由于它们在第一个维度上的大小既不相等,也不为1,无法进行广播操作。在这种情况下,会抛出一个 ValueError,指示帧不对齐(frames are not aligned)。
广播机制在处理不同形状的数组时非常有用,它使得我们能够以更简洁的方式执行元素级操作,并且减少了循环的需求。它在许多科学计在示例中,我们可以看到广播机制的应用。它允许我们在不同形状的数组之间执行元素级操作,而无需进行显式的形状匹配或循环。它大大简化了数组操作的代码编写。
广播机制的规则如下:
-
如果两个数组的维度数不同,在较少的维度上插入尺寸为1的维度,直到维度数相同。
-
如果两个数组在某个维度上的大小相等,或其中一个数组在该维度上的大小为1,则认为它们在该维度上是兼容的。
-
如果两个数组在某个维度上的大小都不相等且都不为1,则它们在该维度上是不兼容的,无法进行广播。
下面是一个更详细的示例,说明广播机制的应用:
import numpy as np
# 示例1:二维数组与一维数组的广播
a = np.array([[1, 2, 3], [4, 5, 6]]) # 形状为(2, 3)
b = np.array([10, 20, 30]) # 形状为(3,)
c = a + b
# 广播后,a的形状为(2, 3),b的形状为(1, 3),c的形状为(2, 3)
# c的值为[[11, 22, 33], [14, 25, 36]]
# 示例2:二维数组与零维标量的广播
d = np.array([[1, 2, 3], [4, 5, 6]]) # 形状为(2, 3)
e = 10 # 标量
f = d + e
# 广播后,d的形状为(2, 3),e的形状为(1, 1),f的形状为(2, 3)
# f的值为[[11, 12, 13], [14, 15, 16]]
# 示例3:三维数组与二维数组的广播
g = np.array([[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]]) # 形状为(2, 2, 3)
h = np.array([[1], [2]]) # 形状为(2, 1)
i = g + h
# 广播后,g的形状为(2, 2, 3),h的形状为(2, 1),i的形状为(2, 2, 3)
# i的值为[[[ 2, 3, 4], [ 6, 7, 8]], [[ 9, 10, 11], [12, 13, 14]]]
在示例1中,我们有一个二维数组 a
和一个一维数组 b
,它们的维度不同。通过广播机制,将数组 b
扩展为 (1, 3)
的形状,然后执行元素级加法操作,得到结果数组 c
。
在示例2中,我们演示了一个二维数组 d
与一个零维标量 e
的广播操作。通过广播机制,将标量 e
扩展为 (1, 1)
的形状,然后执行元素级加法操作,得到结果数组 f
。
在示例3中,我们展示了一个三维数组 g
与一个二维数组 h
的广播操作。通过广播机制,将数组 h
扩展为 (2, 2, 3)
的形状,然后执行元素级加法操作,得到结果数组 i
。
广播机制提供了一种灵活的方法,使得我们可以在不同形状的数组之间进行元素级操作,而无需进行显式的形状匹配或循环。这在处理大规模数据集、执行向量化计算和加速数值计算方面非常有用。
此外,广播机制还可以与其他NumPy操作和函数一起使用,如索引、切片、聚合函数等。通过广播,我们可以方便地对不同形状的数组进行操作,拓展了NumPy在数据处理和科学计算中的应用范围。
需要注意的是,在使用广播机制时,要确保操作是可行且符合预期的。有时候,过度的广播可能会导致意外的结果或错误。因此,在使用广播时,建议仔细检查数组的形状,确保广播操作的正确性。
希望这些信息能够帮助你更好地理解广播机制及其在NumPy中的应用。