基于参考n-dim数组对n-dim数组进行操作的最有效方法

时间:2019-10-29 14:07:05

标签: python arrays numpy vectorization

我有两个形状相同的numpy数组:dat_araref_ara

我想在op_func的{​​{1}}上执行操作axis = -1,但是我只想对每个数组中选定的值切片进行操作,当阈值dat_ara被参考数组thres越过。

为说明起见,在简单的数组只有2维的情况下,我有:

ref_ara

我们看到thres = 4 op_func = np.average ref_ara = array([[1, 2, 1, 4, 3, 5, 1, 5, 2, 5], [1, 2, 2, 1, 1, 1, 2, 7, 5, 8], [2, 3, 2, 5, 1, 6, 5, 2, 7, 3]]) dat_ara = array([[1, 0, 0, 1, 1, 1, 1, 0, 1, 1], [1, 1, 1, 1, 1, 1, 1, 0, 1, 0], [1, 0, 1, 1, 1, 1, 0, 1, 1, 1]]) 的{​​{1}}中第一,第二和第三数组的第五,第七和第三索引中违反了thres。因此,我希望得到的结果是

axis=0

此问题很困难,因为它需要引用ref_ara。如果不是这种情况,我可以简单地使用out_ara = array([op_func(array([1, 0, 0, 1, 1, 1]), op_func(array([1, 1, 1, 1, 1, 1, 1, 0]), op_func(array([1, 0, 1, 1])])

我尝试扩展两个数组的尺寸以将它们关联以进行计算,即:

ref_ara

但是同样,numpy.apply_along_axis要求输入函数只能在1维数组上运行,因此我仍然无法使用该函数。

我知道的另一种方法是明智地遍历数组索引,但是,由于两个数组的尺寸不断变化,这是一件棘手的事情,而且,它的计算效率也不高。

我想尽可能地使用矢量化函数来辅助此过程。最有效的解决方法是什么?

1 个答案:

答案 0 :(得分:1)

这是带掩码数组的一个很好的用例,因为它们使您可以对部分数据执行常规的numpy操作。

让我们假设每一行至少包含一个大于阈值的值。您可以将断点的索引计算为

breaks = np.argmax(ref_ara > thres, axis=-1)   # 5, 7, 3

然后可以使用answer到我先前链接的question来创建掩码。掩码通常是处理numpy中不规则形状数据的最佳方法。

mask = np.arange(ref_ara.shape[-1]) <= breaks.reshape(*breaks.shape, 1)

在这里,我们不需要对arange做任何幻想,因为它沿最后一个维度。如果不是这种情况,您可能想要在范围将要到达的中断形状中插入1,并在范围形状的尾部也添加一个。

现在,掩码数组和ufunc解决方案略有不同。掩码数组版本更通用,因此它是第一个:

data = np.ma.array(data_ara, mask=~mask)

屏蔽数组从普通布尔索引的作用向后解释掩码,因此我们将掩码反转。另外,您可以使用>而不是<=计算掩码。现在的计算很简单:

out_ara = np.ma.average(data, axis=-1).data

一种不太通用的替代方法是将您的操作分解为ufunc,并使用它们提供的屏蔽。对于np.averagenp.sum来说,这很容易,但对于更复杂的操作而言可能会更困难。

从numpy 1.17.0开始,np.sum具有一个where关键字:

out_ara = np.sum(dat_ara, where=mask, axis=-1) / breaks