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

Most efficient way to operate on a n-dim array based on a reference n-dim array

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

我想对 dat_araaxis = -1 执行操作 op_func,但是我只想对每个数组中选定的值切片进行操作,该切片是指定的当参考数组 ref_ara.

超过阈值 thres

为了说明,在数组只是 2-dim 的简单情况下,我有:

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]]) 

我们看到 thresref_araaxis=0 中第 1、2 和 3 数组的第 5、7 和 3 个索引中被破坏。因此我想要的结果是

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.

我试过扩展两个数组的维度以将它们关联起来进行计算,即:

assos_ara = np.append(np.expand_dims(dat_ara, axis=-1), np.expand_dims(ref_ara, axis=-1), axis=-1)

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

我知道的唯一其他方法是通过数组索引明智地迭代,但是,由于数组具有两个数组的不断变化的维度,这是一个棘手的问题,而且,它在计算上效率不高。

我很想使用矢量化函数来帮助这个过程。最有效的方法是什么?

这是屏蔽数组的一个很好的用例,因为它们允许您对部分数据执行正常的 numpy 操作。

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

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

然后您可以使用我之前链接的 to the 创建一个遮罩。掩码通常是处理 numpy 中形状不规则数据的最佳方式。

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

在这里,我们不需要对 arange 做任何花哨的事情,因为它沿着最后一个维度。如果不是这种情况,您可能希望将 1 插入到范围所在的中断形状中,并用 1 填充范围形状的尾部。

现在掩码数组和 ufunc 解决方案略有不同。 masked array版本比较通用,所以排在第一位:

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

掩码数组从正常布尔索引的方式向后解释掩码,因此我们反转掩码。或者,您可以使用 > 而不是 <= 来计算掩码。计算现在很简单:

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

一个不太通用的替代方法是将您的操作分解为 ufunc,并使用它们提供的掩码。这对于 np.average, which is just np.sum and np.divide 来说很容易,但对于更复杂的操作来说可能会更难。

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

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