在向量化NumPy数组上进行移动窗口操作

简介: 在向量化NumPy数组上进行移动窗口操作

今天很有可能你已经做了一些使用滑动窗口(也称为移动窗口)的事情,而你甚至不知道它。例如:许多编辑算法都是基于移动窗口的。在GIS中做地形分析的大多数地形栅格度量(坡度、坡向、山坡阴影等)都基于滑动窗口。很多情况下,对格式化为二维数组的数据进行分析时,都很有可能涉及到滑动窗口。

滑动窗口操作非常普遍,非常有用。它们也很容易在Python中实现。学习如何实现移动窗口将把你的数据分析和争论技能提升到一个新的水平。

什么是滑动窗?

下面的例子显示了一个3×3(3×3)滑动窗口。用红色标注的数组元素是目标元素。这是滑动窗口将计算的新度量的数组位置。例如,在下面的图像中,我们可以计算灰色窗口中9个元素的平均值(平均值也是8),并将其分配给目标元素,用红色标出。你可以计算最小值(0)、最大值(16)或其他一些指标,而不是平均值。对数组中的每个元素都这样做。

就是这样。这就是滑动窗口的基本原理。当然,事情可能变得更加复杂。有限差分方法可以用于时间和空间数据。逻辑可以实现。可以使用更大的窗口大小或非正方形窗口。你懂的。但在其核心,移动窗口分析可以简单地总结为邻居元素的平均值。

需要注意的是,必须为边缘元素设置特殊的调整,因为它们没有9个相邻元素。因此,许多分析都排除了边缘元素。为简单起见,我们将在本文中排除边缘元素。

640.png

样例数组

640.png

3x3的滑动窗口

创建一个NumPy数组

为了实现一些简单的示例,让我们创建上面所示的数组。首先,导入numpy。

importnumpyasnp

然后使用arange创建一个7×7的数组,值范围从1到48。另外,创建另一个包含无数据值的数组,该数组的形状和数据类型与初始数组相同。在本例中,我使用-1作为无数据值。

a=np.arange(49).reshape((7, 7))
b=np.full(a.shape, -1.0)

我们将使用这些数组来开发下面的滑动窗口示例。

通过循环实现滑动窗口

毫无疑问,你已经听说过Python中的循环很慢,应该尽可能避免。特别是在使用大型NumPy数组时。这是完全正确。尽管如此,我们将首先看一个使用循环的示例,因为这是一种简单的方法来概念化在移动窗口操作中发生的事情。在你通过循环示例掌握了概念之后,我们将继续使用更有效的向量化方法。

要实现移动窗口,只需循环遍历所有内部数组元素,识别所有相邻元素的值,并在特定的计算中使用这些值。

通过行和列偏移量可以很容易地识别相邻值。3×3窗口的偏移量如下所示。

640.png

行偏移

640.png

列偏移

循环中NumPy移动窗口的Python代码

我们可以用三行代码实现一个移动窗口。这个例子在滑动窗口内计算平均值。首先,循环遍历数组的内部行。其次,循环遍历数组的内部列。第三,在滑动窗口内计算平均值,并将值赋给输出数组中相应的数组元素。

foriinrange(1, a.shape[0]-1):
forjinrange(1, a.shape[1]-1):
b[i, j] = (a[i-1, j-1] +a[i-1, j] +a[i-1, j+1] +a[i, j-1] +a[i, j] +a[i, j+1] +a[i+1, j-1] +a[i+1, j] +a[i+1, j+1]) /9.0

循环后结果

你将注意到结果与输入数组具有相同的值,但是外部元素没有被分配数据值,因为它们不包含9个相邻元素。

[[-1.-1.-1.-1.-1.-1.-1.]
  [-1.8.9.10.11.12.-1.]
  [-1.15.16.17.18.19.-1.]
  [-1.22.23.24.25.26.-1.]
  [-1.29.30.31.32.33.-1.]
  [-1.36.37.38.39.40.-1.]
  [-1.-1.-1.-1.-1.-1.-1.]]

向量化滑动窗口

Python中的数组循环通常计算效率低下。通过对通常在循环中执行的操作进行向量化,可以提高效率。移动窗口矢量化可以通过同时抵消数组内部的所有元素来实现。

如下图所示。每个图像都有相应的索引。你将注意到最后一张图像索引了所有内部元素,并且对应的图像索引了每个相邻元素的偏移量。

640.png

640.png

640.png

从左到右的偏移索引:[1:-1,:-2],[1:-1,2:],[2 :, 2:]

640.png

640.png

640.png

从左到右的偏移索引:[2 :,:-2],[2 :, 1:-1],[:-2,1:-1]

640.png

640.png

640.png

从左到右的偏移索引:[:-2,2:],[:-2,:-2],[1:-1、1:-1]

Numpy数组上的向量化移动窗口的Python代码

有了上述偏移量,我们现在可以轻松地在一行代码中实现滑动窗口。只需将输出数组的所有内部元素设置为根据相邻元素计算所需输出的函数。

b[1:-1, 1:-1] = (a[1:-1, 1:-1] +a[:-2, 1:-1] +a[2:, 1:-1] +a[1:-1, :-2] +a[1:-1, 2:] +a[2:, 2:] +a[:-2, :-2] +a[2:, :-2] +a[:-2, 2:]) /9.0

矢量化滑动窗口结果

如你所见,这将得到与循环相同的结果。

[[-1.-1.-1.-1.-1.-1.-1.]
  [-1.8.9.10.11.12.-1.]
  [-1.15.16.17.18.19.-1.]
  [-1.22.23.24.25.26.-1.]
  [-1.29.30.31.32.33.-1.]
  [-1.36.37.38.39.40.-1.]
  [-1.-1.-1.-1.-1.-1.-1.]]

速度比较

上述两种方法产生相同的结果,但哪一种更有效?我计算了从5行到100列的数组的每种方法的速度。每种方法对每个测试100次。下面是每种方法的平均时间。

640.png

很明显,向量化的方法更加有效。随着数组大小的增加,循环的效率呈指数级下降。另外,需要注意的是,一个包含10,000个元素(100行和100列)的数组非常小。

总结

移动窗口计算在许多数据分析工作流程中非常常见。这些计算是非常有用的,非常容易实现。然而,使用循环来实现滑动窗口操作是非常低效的。向量化的移动窗口实现不仅更高效,而且使用更少的代码行。一旦掌握了实现滑动窗口的向量化方法,就可以轻松有效地提高工作流程的速度。

目录
相关文章
|
3月前
|
索引 Python
NumPy 教程 之 Numpy 数组操作 28
NumPy 提供多种数组操作功能,包括修改形状、翻转、连接和分割等。本教程重点介绍元素的添加与删除,如使用 `resize`、`append`、`insert` 和 `delete` 函数。其中 `numpy.insert` 可在指定索引前插入值,支持标量或数组插入。示例展示了不同情况下 `insert` 的使用方法,包括不指定轴时的数组扁平化插入,以及沿特定轴进行广播插入。
36 2
|
3月前
|
数据处理 索引 Python
NumPy 数组操作:和普通操作相较,到底蕴含着怎样令人费解的独特魅力?
【8月更文挑战第19天】NumPy是Python科学计算核心库,提供高效数组操作。不同于Python列表直接列举创建,NumPy用`np.array()`创建数组。两者都支持索引和切片,但NumPy性能更优。数学运算方面,NumPy支持简洁的向量化操作,如`my_array * 2`,无需循环。NumPy还简化了数组形状变换,如使用`reshape()`方法。此外,NumPy数组要求元素类型一致,提高了内存使用效率和计算速度。这些特点使NumPy在科学计算和数据分析中不可或缺。
31 0
|
1月前
|
Python
Numpy学习笔记(四):如何将数组升维、降维和去重
本文介绍了如何使用NumPy库对数组进行升维、降维和去重操作。
32 1
|
1月前
|
机器学习/深度学习 并行计算 大数据
【Python篇】NumPy完整指南(上篇):掌握数组、矩阵与高效计算的核心技巧2
【Python篇】NumPy完整指南(上篇):掌握数组、矩阵与高效计算的核心技巧
66 10
|
1月前
|
Python
Numpy学习笔记(五):np.concatenate函数和np.append函数用于数组拼接
NumPy库中的`np.concatenate`和`np.append`函数,它们分别用于沿指定轴拼接多个数组以及在指定轴上追加数组元素。
25 0
Numpy学习笔记(五):np.concatenate函数和np.append函数用于数组拼接
|
1月前
|
Python
使用 NumPy 进行数组操作的示例
使用 NumPy 进行数组操作的示例
|
1月前
|
索引 Python
【Python篇】NumPy完整指南(上篇):掌握数组、矩阵与高效计算的核心技巧1
【Python篇】NumPy完整指南(上篇):掌握数组、矩阵与高效计算的核心技巧
85 4
|
1月前
|
机器学习/深度学习 并行计算 调度
CuPy:将 NumPy 数组调度到 GPU 上运行
CuPy:将 NumPy 数组调度到 GPU 上运行
54 1
|
2月前
|
Python
numpy | 插入不定长字符数组测试OK
本文介绍了如何在numpy中创建和操作不定长字符数组,包括插入和截断操作的测试。
|
2月前
|
API Python
Numpy 数组的一些集合操作
Numpy 数组的一些集合操作
30 0