你的操作包含许多条件语句,因此在一般情况下(任何类型的条件语句,任何类型的操作)最有效的方法是使用循环。可以使用numba或cython来高效地完成这项工作。在特殊情况下,你可以使用numpy/scipy中的更高级别函数进行实现。我将展示一个特定示例的解决方案,希望你可以从中推广。
首先使用一些虚假数据:
A = np.asarray([
[1, 1, 1, 2, 0],
[1, 0, 2, 2, 2],
[0, 2, 0, 1, 0],
[1, 2, 2, 1, 0],
[2, 1, 1, 1, 2]
])
我们将在A
中找到符合各种条件的位置。
- 1a)该值为1
- 1b)该值大于其水平邻居
- 2a)该值为2
- 2b)该值大于其对角线邻居
查找A
中出现指定值的位置:
cond1a = A == 1
cond2a = A == 2
这将生成一个布尔值矩阵,其大小与A
相同。当条件成立时,值为true,否则为false。
查找A
中每个元素与其相邻元素之间的指定关系的位置:
f1 = np.asarray([[1, 0, 1]])
cond1b = A > scipy.ndimage.maximum_filter(
A, footprint=f1, mode='constant', cval=-np.inf)
f2 = np.asarray([
[0, 0, 1],
[0, 0, 0],
[1, 0, 0]
])
cond2b = A > scipy.ndimage.maximum_filter(
A, footprint=f2, mode='constant', cval=-np.inf)
与之前类似,这会给出一个由布尔值矩阵组成的结果,指示条件的真假。此代码使用
scipy.ndimage.maximum_filter()。该函数迭代地将一个“足印”移动到
A
的每个元素中心。该位置返回值为足印元素值等于1的所有元素的最大值。参数
mode
指定如何处理矩阵边缘外的隐式值,即足印超出矩阵范围时的情况。在这里,我们将它们视为负无穷大,这与忽略它们相同(因为我们使用了最大操作)。
根据条件设置结果的值。如果条件1a和1b都成立,或者如果条件2a和2b都成立,则该值为999。否则,该值为0。
result = np.zeros(A.shape)
result[(cond1a & cond1b) | (cond2a & cond2b)] = 999
结果如下:
[
[ 0, 0, 0, 0, 0],
[999, 0, 0, 999, 999],
[ 0, 0, 0, 999, 0],
[ 0, 0, 999, 0, 0],
[ 0, 0, 0, 0, 999]
]
您可以通过更改过滤器印记来将此方法推广到其他邻居模式。您可以使用其他类型的过滤器(请参见
scipy.ndimage)将其推广到其他操作(最小值、中位数、百分位数等)。对于可以表示为加权和的操作,请使用
二维交叉相关。
这种方法应该比在Python中循环要快得多。但是,它确实执行了不必要的计算(例如,仅当值为1或2时才需要计算最大值,但我们正在为所有元素进行计算)。手动循环可以让您避免这些计算。在Python中循环可能比这里的代码要慢得多。但是,在numba或cython中实现它可能会更快,因为这些工具生成编译代码。