NumPy中的广播机制是一种非常强大的功能,可以允许不同形状的数组进行运算。广播机制使得数组的运算更加灵活、简洁,避免了手动调整数组形状的需求。但是,广播机制尤其使用的条件,什么时候两个不同形状的数组可以直接进行运算,什么时候又不能,有些老手有时候也需要稍微停顿、思考。
本文就来重点介绍下NumPy中的广播机制。
本文的内容主要有:
1、NumPy数组运算的基本原理
2、什么是广播机制
3、可广播数组的条件
4、使用广播的优势与注意事项
NumPy数组运算的基本原理在NumPy中数组之间运算的基本原理是“element-by-element”。
也就是说,两个数组之间运算时,是逐个元素地对数组对进行计算。从一个数组中取出一个元素,从另一个数组中找出与之位置相对应的数组。
所以,通常情况下,两个进行运算的数组,必须具有相同的形状。
比如:
但是,element-by-element的基本原理,如果要求形状完全相同,有时候显得过于苛刻。每次进行计算,可能都需要手动调整参与运算的数组形状,才能进行运算。
为了简化数组间的运算,NumPy提供了广播机制,从而当数组的形状满足某些规则时,也能直接运算,而不要求形状完全相同。
什么是广播机制所谓广播机制,是指当数组进行运算时,如果两个数组的形状不同,NumPy会尝试通过“广播”的方式使它们的形状一致,从而进行element-by-element的元素级操作。
广播的基本思想是通过“虚拟”复制的方式,将较小的数组扩展到较大的数组的形状。最终使得参与运算的两个数组变为形状完全相同的两个数组。
广播机制提供了一种矢量化/向量化数组操作的方法,将循环任务在C语言中完成,而不是在Python中完成,从而提高运算执行的效率。
此外,由于无需进行不必要的数据复制,而且通常在底层采用高效的算法实现,使得在代码编写和执行效率上都得到一定的优化。
但是,需要注意的是,在某些情况下,默认的广播机制可能会导致内存使用效率的低下,从而减慢计算速度。
前面介绍过的数组与标量(数字)之间的运算,可以理解为最简单的一种广播形式。
比如下面的代码:
实际的广播执行,类似于下图的示例:
当然,所谓的stretch(拉伸)只是一个概念性的类比,NumPy最够聪明,可以在不实际进行数据复制的情况下使用原始标量值,一遍广播操作尽可能高效地进行内存计算。
可广播数组的条件数组与标量的运算只是广播中的一个极简的特例,更通用的广播机制,只需要两个数组的形状满足如下的规则即可触发:
1、维数相同或者形状可以通过添加1来匹配
通常来说,两个数组的维度应该相同,如果维度不同,NumPy会在较小的数组的前面添加1直到两个数组的维度相同。
2、维度大小相同或者其中一方为1
通过在形状前面加1,使得两个数组的维数相同之后,对两个数组逐个维度进行大小的比较,要么该维度大小相同,要么任意一方大小为1。
只要满足了这两个条件,即可进行广播运算。
下面举例说明一下:
一个大小为256x256的RGB图像(3个通道),与一个只有3个值的一维数组,可以通过广播直接进行乘法运算:
更复杂的,可以两个数组的形状都进行拉伸,比如:
通过代码简单演示一下两个数组都进行拉伸的广播:
上述代码的广播过程如下图所示:
通常情况下,NumPy的广播机制能够带来一些优势,但是,在某些情况下,也可能产生不良影响。
广播机制的优势,在前面已经介绍了,这里简单总结一下:
1、简化代码编写:广播使得数组运算更加简洁,无需显式地调整数组的形状。
2、提高运算性能:通过避免显式复制,广播可以减少内存消耗,提高计算效率。
3、灵活性:能够处理不同形状的数组,方便地进行向量化运算。
尽管广播机制功能强大,但在某些情况下也可能带来潜在的问题或者影响:
1、内存消耗:在某些情况下,广播可能会导致内存消耗增加,特别是当小数组被“虚拟复制”成大数组时。
2、性能问题:在某些计算性能敏感的场景中,广播可能反而导致性能下降,尤其是当涉及多个维度的大数组时。
3、隐式错误:由于广播机制,可能会出现一些难以发现的错误,比如意外的数组形状不匹配,或者逻辑上的错误等。由于广播,可能难以发现这些错误。
总结本文首先介绍了NumPy中element-by-element的基本原理,引出了广播机制,然后介绍了NumPy中广播的触发规则,其间,通过代码及示意图的方式演示了广播的执行过程。最后总结了广播机制的优势以及在使用中需要注意的事项。
以上就是本文的全部内容,感谢您的拨冗阅读!