更快地估计对数运算

时间:2017-09-22 19:55:15

标签: python performance numpy logarithm

我有一个相当简单的函数,涉及基数10的对数(f1如下所示)。我需要它尽可能快地运行,因为它作为更大代码的一部分被称为数百万次。

我尝试使用Taylor approximationf2以下),但即使进行大规模扩展,准确性也很差,甚至更糟,最终会花费更多时间。

我是否已达到numpy可达到的效果限制?

import time
import numpy as np

def f1(m1, m2):
    return m1 - 2.5 * np.log10(1. + 10 ** (-.4 * (m2 - m1)))


def f2(m1, m2):
    """
    Taylor expansion of 'f1'.
    """
    x = -.4 * (m2 - m1)
    return m1 - 2.5 * (
        0.30102999 + .5 * x + 0.2878231366 * x ** 2 -
        0.0635837 * x ** 4 + 0.0224742887 * x ** 6 -
        0.00904311879 * x ** 8 + 0.00388579 * x ** 10)


# The data I actually use has more or less this range.
N = 1000
m1 = np.random.uniform(5., 30., N)
m2 = np.random.uniform(.7 * m1, m1)

# Test both functions
M = 5000
s = time.clock()
for _ in range(M):
    mc1 = f1(m1, m2)
t1 = time.clock() - s
s = time.clock()
for _ in range(M):
    mc2 = f2(m1, m2)
t2 = time.clock() - s

print(t1, t2, np.allclose(mc1, mc2, 0.01))

2 个答案:

答案 0 :(得分:3)

使用乘法替换f2中的所有指数:

def f2(m1, m2):
    """
    Taylor expansion of 'f1'.
    """
    x = -0.4 * (m2 - m1)
    x2 = x * x
    x4 = x2 * x2
    x6 = x4 * x2
    return m1 - 2.5 * (
        0.30102999 + .5 * x + 0.2878231366 * x2 -
        0.0635837 * x4 + 0.0224742887 * x6 -
        0.00904311879 * x4 * x4 + 0.00388579 * x4 * x6)

答案 1 :(得分:3)

使用此代码段,我不确定您是否应优化日志,但更多的是整个vector-expression本身

你可以试试numexpr(Python的快速数值数组表达式求值器,NumPy,...),这可能对你有很大帮助。

尝试这个的想法来自Ignacio的评论,这让我想到了他的加速来自哪里(我敢肯定,它不是来自日志计算本身)。

在我对代码的简单修改中:

import numexpr as ne
def f1(m1, m2):
   return ne.evaluate("m1 - 2.5 * log10( 1.0 + 10 ** (-0.4 * (m2-m1)))")

以上似乎(未经优化的)f2(近似值)<5> 6倍,同时仍然保持原始精度。

几乎是原始numpy-approach f1 的两倍

这些数字可能会根据numexpr的设置而改变,因为例如也可以使用Intels MKL。由于我懒得检查我的基于anaconda的设置,我提供的这只是一个技术演示,每个人都可以尝试。

虽然我过去曾经使用过几次对于简单的东西,但我可以补充说,它也在pandas中使用,只是提到一个真实世界的项目,取决于它的正确运作。

免责声明:我使用您的基准作为模板(希望缓存和co不起作用)。