2016-12-04 137 views
0

scipy.special中的expit函数是一个向量化的sigmoid函数。它计算1 /(1 + e ^( - x)),这很复杂,可能涉及泰勒级数。我学习了“快速S形”,1 /(1 + abs(x)),它应该快得多 - 但内建的expit函数大大优于它,即使我把它作为lambda表达式到numpy.vectorize。numpy.vectorize:为什么这么慢?

这里有一种方法来测试他们:

from scipy.special import expit 
data = np.random.rand(1000000) 

内置的,复杂的乙状结肠是快:

%prun expit(data) 

3 function calls in 0.064 seconds 

Ordered by: internal time 

ncalls tottime percall cumtime percall filename:lineno(function) 
    1 0.064 0.064 0.064 0.064 <string>:1(<module>) 
    1 0.000 0.000 0.064 0.064 {built-in method builtins.exec} 
    1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects} 

比较简单的乙状结肠是20倍左右慢:

%prun np.vectorize(lambda x: (x/(1 + abs(x)) + 1)/2)(data) 

2000023 function calls in 1.992 seconds 

Ordered by: internal time 

ncalls tottime percall cumtime percall filename:lineno(function) 
1000001 1.123 0.000 1.294 0.000 <string>:1(<lambda>) 
     1 0.558 0.558 1.950 1.950 function_base.py:2276(_vectorize_call) 
1000001 0.170 0.000 0.170 0.000 {built-in method builtins.abs} 
     4 0.098 0.025 0.098 0.025 {built-in method numpy.core.multiarray.array} 
     1 0.041 0.041 1.991 1.991 function_base.py:2190(__call__) 
     1 0.000 0.000 0.068 0.068 function_base.py:2284(<listcomp>) 
     1 0.000 0.000 1.992 1.992 {built-in method builtins.exec} 
     1 0.000 0.000 1.991 1.991 <string>:1(<module>) 
     1 0.000 0.000 0.000 0.000 function_base.py:2220(_get_ufunc_and_otypes) 
     1 0.000 0.000 0.000 0.000 function_base.py:2162(__init__) 
     1 0.000 0.000 0.000 0.000 function_base.py:2242(<listcomp>) 
     2 0.000 0.000 0.000 0.000 numeric.py:414(asarray) 
     1 0.000 0.000 0.000 0.000 {built-in method numpy.core.umath.frompyfunc} 
     1 0.000 0.000 0.000 0.000 function_base.py:2266(<listcomp>) 
     2 0.000 0.000 0.000 0.000 {built-in method builtins.isinstance} 
     1 0.000 0.000 0.000 0.000 {built-in method builtins.len} 
     1 0.000 0.000 0.000 0.000 {method 'join' of 'str' objects} 
     1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler' objects} 

回答

2

为什么numpy.vectorize很慢的问题几乎可以肯定的问过,但在一个简短的搜索中,我没有发现明显使这个问题重复的问题。为了在这里回答它,我只需引用vectorize docstring:“向量化函数主要是为了方便,而不是为了性能,实现本质上是for循环。”

您想快速制作1/(1 + abs(x))。 numpy有一个名为numpy.abs的函数(也叫做numpy.absolute - 它们是同一个对象的不同名称)。它计算它的参数的每个元素的绝对值,并且它在C代码中这样做,所以它很快。此外,Python内置函数abs知道如何将参数派发到具有numpy数组所做的__abs__方法的对象,因此您还可以使用Python的abs()来计算numpy数组的元素方向绝对值。但在下面,我将使用np.abs

下面是使用np.abs的例子:

In [25]: x = np.array([-2, -1.5, 0, 5, 10]) 

In [26]: np.abs(x) 
Out[26]: array([ 2. , 1.5, 0. , 5. , 10. ]) 

这里是scipy.special.expit1.0/(1 + np.abs(x))性能的一个大阵x一个对比:

In [34]: from scipy.special import expit 

In [35]: x = np.random.randn(100000) 

In [36]: %timeit expit(x) 
1000 loops, best of 3: 771 µs per loop 

In [37]: %timeit 1.0/(1 + np.abs(x)) 
1000 loops, best of 3: 279 µs per loop 

所以1.0/(1 + np.abs(x))是相当快一点比expit(x)

+0

我测试过;这绝对解决了我的问题。谢谢,沃伦! –