【问题标题】:Improving performance of complex logical conditions on numpy arrays提高 numpy 数组上复杂逻辑条件的性能
【发布时间】:2019-03-24 15:32:17
【问题描述】:

我需要在一个大型二维“NUMPY”数组上评估许多逻辑条件,并将整体结果收集到一个布尔“RESULT”numpy 数组中。

所有条件都用 AND 语句链接的简单示例可能是:

RESULT= cond1(NUMPY) & cond2(NUMPY) & cond3(NUMPY) & ....

我想了解是否有优化性能的方法。

例如,在这种情况下,如果 NUMPY 数组中的大多数值的第一个条件 (cond1) 为 False,则评估这些值的所有其他条件将浪费资源,因为 AND 条件无论如何都会生成 False在最终的 RESULT 数组中。

有什么想法吗?

【问题讨论】:

  • Python and 和 or 短路,但仅适用于标量条件。使用整个numpy 整个数组操作,评估每个条件,然后组合值。您必须使用 numba 或 cython 来构建更快的迭代测试来实现短路。
  • 感谢您的解释和建议,我对 numba 和 cython 还不是很熟悉,但如果我没有找到其他方法,我会研究它们 :)

标签: python performance numpy optimization logic


【解决方案1】:

您可以手动进行短路,但我应该补充一点,这可能只在相当极端的情况下才值得。

这里是 99 个链式逻辑与的示例。使用where 关键字或使用花哨的索引来完成短路。第二个但不是第一个为这个例子提供了不错的速度。

import numpy as np

a = np.random.random((1000,))*1.5
c = np.random.random((100, 1))*1.5

def direct():
    return ((a+c) < np.arccos(np.cos(a+c)*0.99)).all(0)

def trickya():
    out = np.ones(a.shape, '?')
    for ci in c:
        np.logical_and(out, np.less(np.add(a, ci, where=out), np.arccos(np.multiply(np.cos(np.add(a, ci, where=out), where=out), 0.99, where=out), where=out), where=out), out=out, where=out)
    return out

def trickyb():
    idx, = np.where((a+c[0]) < np.arccos(np.cos(a+c[0])*0.99))
    for ci in c[1:]:
        idx = idx[(a[idx]+ci) < np.arccos(np.cos(a[idx]+ci)*0.99)]
    out = np.zeros(a.shape, '?')
    out[idx] = True
    return out

assert (direct()==trickya()).all()
assert (direct()==trickyb()).all()

from timeit import timeit

print('direct  ', timeit(direct, number=100))
print('where kw', timeit(trickya, number=100))
print('indexing', timeit(trickyb, number=100))

示例运行:

direct   0.49512664100620896
where kw 0.494946873979643
indexing 0.17760096595156938

【讨论】:

  • 非常有趣!我会尝试看看是否可以使用类似的方式来加速我的代码:)。谢谢!
猜你喜欢
  • 2022-01-21
  • 2016-08-28
  • 2019-09-13
  • 2019-12-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-16
  • 2018-01-08
相关资源
最近更新 更多