Python中的矢量化和广播

已发表: 2020-12-01

矢量化和广播是在使用 Numpy 进行数学运算时加快计算时间和优化内存使用的方法。 这些方法对于确保降低时间复杂度以使算法不会面临任何瓶颈至关重要。 这种优化的操作对于应用程序的可扩展性是必要的。 我们将介绍这两种技术并实现一些示例。

在本教程结束时,您将掌握以下知识:

  • Numpy 如何处理向量化
  • 有和没有矢量化的时间差
  • 什么是广播
  • 广播与通常的矩阵乘法有何不同

矢量化

很多时候,我们需要对数组进行数学运算——比如数组乘法。 现在,一种非向量化的方法是使用循环进行元素乘法。 以这种方式实现它会导致多次执行相同的乘法运算,如果数据量太大,这将浪费计算资源。 让我们快速浏览一下。

非矢量化方式:

随机导入

a = [random.randint( 1 , 100 ) for _ in range( 10000 )]
b = [random.randint( 1 , 100 ) for _ in range( 10000 )]
%timeit [i*j for i, j in zip(a,b)]

#输出:
>> 1000 个循环,最好的3 个每个循环658 µs

矢量化方式:

numpy导入np
a = np.array([random.randint( 1 , 100 ) for _ in range( 10000 )])
b = np.array([random.randint( 1 , 100 ) for _ in range( 10000 )])
%timeit a*b

#输出:
>> 100000循环, 3 个中最好的每个循环7.25 µs

如我们所见,经过的时间从 658 微秒变为仅 7.25 微秒。 这是因为当我们说a = np.array([])时,所有操作都由 numpy 内部处理。 当我们执行a*b,numpy 在内部通过向量化的方式一次将整个数组相乘。

在这里,我们使用 %timeit 魔术命令来计时进程的执行时间,这可能在您的机器上有所不同。

让我们看一下维度为 (nx1) 和 (1xm) 的 2 个向量的外积的另一个示例。 输出将是 (nxm)。

进口时间
导入numpy
导入数组
a = array.array( 'i' , [random.randint( 1 , 100 ) for _ in range( 100 )])
b = array.array( 'i' , [random.randint( 1 , 100 ) for _ in range( 100 )])

T1 = time.process_time()
c = numpy.zeros(( 200 , 200 ))

对于范围内(len(a)):
对于范围内j (len(b)):
c[i][j]= a[i]*b[j]

T2 = time.process_time()

print( f”计算时间 = { 1000 *(T2-T1)} ms” )

#输出:
>> 计算时间 = 6.819299000000001毫秒

现在,让我们用 Numpy 来做吧,

T1 = time.process_time()
c = numpy.outer(a, b)
T2 = time.process_time()

print( f”计算时间 = { 1000 *(T2-T1)} ms” )

#输出:
>> 计算时间 = 0.2256630000001536 ms

正如我们再次看到的,Numpy 通过矢量化更快地处理相同的操作方式。

必读:现实世界中令人着迷的 Python 应用程序

广播

所以到目前为止,我们看到了使用相同大小数组的示例。 如果数组的大小不同怎么办? 这里是 Numpy 的另一个很棒的功能,广播,出现的地方。

广播是向量化的另一个扩展,其中数组不需要具有相同的大小,以便对其执行加法、减法、乘法等操作。让我们通过一个非常简单的数组和标量相加示例来理解这一点。

a = np.array([ 1 , 1 , 1 , 1 ])
一个+ 5

#输出:
数组([ 6 , 6 , 6 , 6 ])

正如我们所见,标量 5 被添加到所有元素中。 那么它是怎么发生的呢?

想象一下这个过程,你可以认为标量 5 重复 4 次以形成一个数组,然后将其添加到数组 a 中。 但请记住,Numpy 不会创建任何此类只会占用内存的数组。 Numpy 只是“广播”或复制标量 5 到 4 个位置以将其添加到数组 a。

让我们再举一个简单的例子。

a = np.ones(( 3 , 3 ))
b = np.ones( 3 )
a+b

#输出:
>> 数组([[ 2. , 2. , 2. ],
[ 2. , 2. , 2. ],
[ 2. , 2. , 2. ]])

在上面的示例中,形状 (3,1) 的数组被广播到 (3,3) 以匹配数组 a。

但这是否意味着任何维度的数组都可以通过广播来匹配任意维度的数组呢?

不!

广播规则

Numpy 遵循一组简单的规则来确保只广播符合条件的数组。 让我们来看看。

广播规则说要操作的 2 个数组必须具有相同的维度,或者如果它们中的任何一个为 1。

让我们看看这是在行动。

示例 1:

考虑以下维度数组:

a = 3 x 4 x 7

b = 3 x 4 x 1

这里 b 的最后一个维度将被广播以匹配 a 到 7 的维度。

因此,结果 = 3 x 4 x 7

示例 2:

a = 3 x 4 x 7

b = 4

现在,a 和 b 的维数不相等。 在这种情况下,维数较少的数组将用 1 填充。

所以,在这里,b 的第一个和最后一个维度都是 1,因此它们将被广播以匹配 a 到 3 和 7。

因此,结果 = 3 x 4 x 7。

阅读: Python 教程

示例 3:

a = 3 x 4 x 1 x 5

b = 3 x 1 x 7 x 1

同样,b 的第二个和最后一个维度将被广播以匹配 a 的 4 和 5。此外,a 的第三个维度将被广播以匹配 b 的 7。

因此,结果 = 3 x 4 x 7 x 5

现在让我们看看条件何时失败:

示例 4:

a = 3 x 4 x 7 x 5

b = 3 x 3 x 7 x 4

在这里,b的第二个和第四个维度与a不匹配,也不是1。在这种情况下,Python会抛出一个值错误:

ValueError 操作无法形状 3、4、7、5 3、3、7、4 一起广播_ _ _ _ _ _

示例 5:

a = 3 x 4 x 1 x 5

b = 3 x 2 x 3

结果:值错误

在这里,第二个维度也不匹配,并且它们中的任何一个都不是 1。

在你走之前

矢量化和广播都是 Numpy 优化和更高效处理的方法。 这些概念应该牢记在心,尤其是在处理图像数据和神经网络中非常常见的矩阵和 n 维数组时。

如果您想了解 Python、数据科学,请查看 IIIT-B 和 upGrad 的数据科学 PG 文凭,该文凭专为在职专业人士而设,提供 10 多个案例研究和项目、实用的实践研讨会、与行业专家的指导,与行业导师一对一,400 多个小时的学习和顶级公司的工作协助。

Python中的向量化是什么?

Numpy 是一个 Python 包,它提供了几个标准的数学函数,可以在不需要循环的情况下对大型数据数组进行快速操作,包括矢量化。 矢量化用于在不使用循环的情况下加速 Python 程序。 使用这种方法可以帮助减少执行代码所花费的时间。 对向量执行各种操作,例如向量的点积,也称为标量积,因为它产生单个输出,外积,其结果是维度等于长度 x 长度的方阵向量,逐元素乘法,它产生具有相同索引的元素。

什么是 Python 中的广播?

广播一词是指 Numpy 在导致特定限制的算术运算期间如何管理具有不同维度的数组; 较小的阵列在巨大的阵列中广播,以便它们的形式是一致的。 广播允许您对数组操作进行向量化,以便循环在 C 中进行,而不是像 Numpy 那样在 Python 中进行。 它在不创建不必要的数据副本的情况下实现了这一点,从而实现了高效的算法实现。 在某些情况下,广播是一个负面的想法,因为它会导致浪费的内存消耗,从而减慢处理速度。

NumPy 在 Python 中的用途是什么?

NumPy 或 Numerical Python 是一个免费的开源 Python 库,几乎被每个研究和工程分支所使用。 NumPy 库包括多维数组和矩阵数据结构,并提供有效操作数组(同质 n 维数组对象)的方法。 用户可以使用 NumPy 对数组执行广泛的数学运算。 它通过强大的数据结构增强了 Python,这些数据结构提供了使用数组和矩阵的高效计算,以及处理这些数组和矩阵的大量高级数学函数库。