简体   繁体   English

numpy的log函数会发生什么? 有什么方法可以提高性能?

[英]What happens in numpy's log function? Are there ways to improve the performance?

I have a computation project with heavy use of log function (for integers), billions of calls. 我有一个计算项目,大量使用对数函数(对于整数),数十亿次调用。 I find the performance of numpy's log is surprisingly slow. 我发现numpy日志的性能出奇地慢。

The following code takes 15 to 17 secs to complete: 以下代码需要15到17秒才能完成:

import numpy as np
import time

t1 = time.time()
for i in range(1,10000000): 
    np.log(i)
t2 = time.time()
print(t2 - t1)

However, the math.log function takes much less time from 3 to 4 seconds. 但是,math.log函数花费的时间要少得多,从3到4秒。

import math
import time

t1 = time.time()
for i in range(1,10000000): 
    math.log(i)
t2 = time.time()
print(t2 - t1)

I also tested matlab and C#, which takes about 2 secs and just 0.3 secs respectively. 我还测试了matlab和C#,它们分别花费大约2秒和0.3秒。

matlab Matlab的

tic
for i = 1:10000000
    log(i);
end
toc

C# C#

var t = DateTime.Now;
for (int i = 1; i < 10000000; ++i)
     Math.Log(i);
Console.WriteLine((DateTime.Now - t).TotalSeconds);

Is there any way in python that I can improve the performance of log function? python中有什么方法可以改善日志功能的性能吗?

NumPys functions are designed for arrays not for single values or scalars. NumPys函数是为数组设计的,不适用于单个值或标量。 They have a rather high overhead because they do several checks and conversions that will provide a speed benefit for big arrays but these are costly for scalars. 它们具有相当高的开销,因为它们会进行多次检查和转换,这将为大型阵列带来速度上的好处,但对于标量而言,这是昂贵的。

The conversion is really obvious if you check the type of the return: 如果检查返回的类型,则转换非常明显:

>>> import numpy as np
>>> import math

>>> type(np.log(2.))
numpy.float64
>>> type(math.log(2.))
float

On the other hand the math -module is optimized for scalars. 另一方面, math module已针对标量进行了优化。 So they don't need that many checks (I think there are only two: Convert to float and check is it's <= 0 ). 因此,他们不需要那么多检查(我认为只有两个检查:转换为float并检查它是否<= 0 )。 Which is why math.log is faster for scalars compared to numpy.log . 这就是为什么math.log 对于标量而言要比numpy.log更快 numpy.log

But if you operate on arrays and want to take the logarithm of all elements in the array NumPy can be much faster. 但是,如果您对数组进行操作并希望获取数组中所有元素的对数,则NumPy可以更快。 On my computer if I time the execution of np.log on an array compared to math.log of each item in a list then the timing looks different: 在我的计算机上,如果我将数组中np.log的执行时间与math.log中每个项目的np.log进行比较,则计时看起来会不同:

arr = np.arange(1, 10000000)
%timeit np.log(arr)
201 ms ± 959 µs per loop (mean ± std. dev. of 7 runs, 1 loop each)

lst = arr.tolist()
%timeit [math.log(item) for item in lst]
8.77 s ± 63.8 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

So np.log will be many orders of magnitude faster on arrays (it's more than 40 times faster in this case)! 因此, np.log在阵列上的速度将提高多个数量级(在这种情况下,速度将提高40倍以上)! And you don't need to write any loop yourself. 而且您不需要自己编写任何循环。 As ufunc np.log will also correctly work on multidimensional numpy arrays and also allows to do the operation inplace. 作为np.log也可以在多维numpy数组上正常工作,并且允许就地进行操作。

As a rule of thumb: If you have an array with thousands of items NumPy will be faster, if you have scalars or only a few dozen items math + explicit loop will be faster. 根据经验:如果您有一个包含数千个项目的数组,那么NumPy会更快,如果您有标量或只有几十个项目,那么math +显式循环会更快。


Also don't use time for timing code. 也不要将time用于计时代码。 There are dedicated modules that give more accurate results, better statistics and disable garbage collection during the timings: 有专用的模块可以提供更准确的结果,更好的统计信息并在计时期间禁用垃圾收集:

I generally use %timeit which is a convenient wrapper around the timeit functionality, but it requires IPython . 我通常使用%timeit ,它是围绕timeit功能的便捷包装,但是它需要IPython They already conveniently display the result mean and deviation and do some (mostly) useful statistics like displaying the "best of 7" or "best of 3" result. 他们已经方便地显示了结果的均值和偏差,并做了一些(大部分)有用的统计数据,例如显示“ 7中最佳”或“ 3中最佳”结果。


I recently analyzed the runtime behaviour of numpy functions for another question , some of the points also apply here. 我最近对numpy函数的运行时行为进行了分析,得出了另一个问题 ,其中一些要点也适用于此。

Interestingly, the issue of the python standard library being slow doesn't replicate on my machine (Windows 10, running Python 2.7.11 and numpy 1.11.0). 有趣的是,python标准库运行缓慢的问题并未在我的机器上复制(Windows 10,运行python 2.7.11和numpy 1.11.0)。

>>> t1 = time.time()
>>> for i in range(1,10000000): 
>>>     _ = np.log(i)
>>> t2 = time.time()
>>> print(t2 - t1)
9.86099982262
>>> t1 = time.time()
>>> for i in range(1,10000000): 
>>>     _ = math.log(i)
>>> t2 = time.time()
>>> print(t2 - t1)
2.48300004005

Similar to your performance in Matlab. 与您在Matlab中的表现类似。 @Nils raises a good point though, numpy is designed to be efficient on arrays. @Nils提出了一个很好的观点,numpy被设计为在数组上有效。

>>> t1 = time.time()
>>> for i in range(1,1000): 
>>>     _ = np.log(np.arange(1,10000))
>>> t2 = time.time()
>>> print(t2 - t1)
0.146000146866
>>> t1 = time.time()
>>> for i in range(1,1000): 
>>>     _ = [math.log(i) for i in range(1,10000)]
>>> t2 = time.time()
>>> print(t2 - t1)
2.3220000267

If you can vectorize your input, numpy will outperform the standard math library and even come close to C#. 如果可以对输入进行矢量化处理,则numpy的性能将超过标准数学库,甚至接近C#。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM