对“稀疏”numpy数组的部分进行高效的数学运算

时间:2011-03-11 17:13:59

标签: python arrays numpy mask slice

我在博士论文的模拟中面临以下挑战:

我需要优化以下代码:

repelling_forces = repelling_force_prefactor * np.exp(-(height_r_t/potential_steepness))

在这段代码中,'height_r_t'是一个真正的Numpy数组,'potential_steepness'是一个标量。 'repelling_force_prefactor'也是一个Numpy数组,它主要是ZERO,但是在预先计算的位置有一个,它在运行时不会改变(即一个Mask)。 显然代码是低效的,因为只计算位置处的指数函数会更有意义,其中'repelling_force_prefactor'非零。

问题是我如何以最有效的方式做到这一点?

我现在唯一的想法是使用'repelling_force_prefactor'将切片定义为'height_r_t'并将'np.exp'应用于这些切片。但是,我已经获得了切片很慢的经验(不确定这一般是否正确)并且解决方案看起来很尴尬。

正如旁注中那样,'repelling_force_prefactor'中1到0的比例约为1/1000,我在循环中运行它,因此效率非常重要。 (评论:我在使用Cython方面没有问题,因为我需要/想要在某个时候学习它...但我是新手,所以我需要一个好的指针/解释。)< / p>

2 个答案:

答案 0 :(得分:3)

屏蔽数组完全是出于您的目的而实现的。

表现与Sven的答案相同:

height_r_t = np.ma.masked_where(repelling_force_prefactor == 0, height_r_t)
repelling_forces = np.ma.exp(-(height_r_t/potential_steepness))

屏蔽数组的优点是你不必切片和扩展数组,大小总是相同的,但是numpy自动知道不计算数组被屏蔽的exp。

此外,您可以使用不同的掩码对数组求和,并且生成的数组具有掩码的交集。

答案 1 :(得分:2)

切片可能比计算所有指数要快得多。我没有使用掩码repelling_force_prefactor直接进行切片,而是建议预先计算非零的索引,并将它们用于切片:

# before the loop
indices = np.nonzero(repelling_force_prefactor)

# inside the loop
repelling_forces = np.exp(-(height_r_t[indices]/potential_steepness))

现在repelling_forces将仅包含非零的结果。如果您必须使用此值更新height_r_t原始形状的某些数组,则可以再次使用indices切片,或使用np.put()或类似函数。

在这种情况下,使用索引列表进行切片比使用布尔掩码进行切片更有效,因为索引列表缩短了千倍。实际上衡量表现当然取决于你。