我有以下numpy ndarray。
[ -0.54761371 17.04850603 4.86054302]
我想将此函数应用于数组的所有元素
def sigmoid(x):
return 1 / (1 + math.exp(-x))
probabilities = np.apply_along_axis(sigmoid, -1, scores)
这是我得到的错误。
TypeError: only length-1 arrays can be converted to Python scalars
我做错了什么。
答案 0 :(得分:7)
函数numpy.apply_along_axis
不适用于此目的。
尝试使用numpy.vectorize
对您的函数进行矢量化:https://docs.scipy.org/doc/numpy/reference/generated/numpy.vectorize.html
此函数定义了一个矢量化函数,它将嵌套的对象序列或numpy数组作为输入,并返回numpy数组的单个或元组作为输出。
import numpy as np
import math
# custom function
def sigmoid(x):
return 1 / (1 + math.exp(-x))
# define vectorized sigmoid
sigmoid_v = np.vectorize(sigmoid)
# test
scores = np.array([ -0.54761371, 17.04850603, 4.86054302])
print sigmoid_v(scores)
输出:[ 0.36641822 0.99999996 0.99231327]
性能测试表明scipy.special.expit
是计算逻辑函数和矢量化变量的最佳解决方案,最糟糕的是:
import numpy as np
import math
import timeit
def sigmoid_(x):
return 1 / (1 + math.exp(-x))
sigmoidv = np.vectorize(sigmoid_)
def sigmoid(x):
return 1 / (1 + np.exp(x))
print timeit.timeit("sigmoidv(scores)", "from __main__ import sigmoidv, np; scores = np.random.randn(100)", number=25),\
timeit.timeit("sigmoid(scores)", "from __main__ import sigmoid, np; scores = np.random.randn(100)", number=25),\
timeit.timeit("expit(scores)", "from scipy.special import expit; import numpy as np; scores = np.random.randn(100)", number=25)
print timeit.timeit("sigmoidv(scores)", "from __main__ import sigmoidv, np; scores = np.random.randn(1000)", number=25),\
timeit.timeit("sigmoid(scores)", "from __main__ import sigmoid, np; scores = np.random.randn(1000)", number=25),\
timeit.timeit("expit(scores)", "from scipy.special import expit; import numpy as np; scores = np.random.randn(1000)", number=25)
print timeit.timeit("sigmoidv(scores)", "from __main__ import sigmoidv, np; scores = np.random.randn(10000)", number=25),\
timeit.timeit("sigmoid(scores)", "from __main__ import sigmoid, np; scores = np.random.randn(10000)", number=25),\
timeit.timeit("expit(scores)", "from scipy.special import expit; import numpy as np; scores = np.random.randn(10000)", number=25)
结果:
size vectorized numpy expit
N=100: 0.00179314613342 0.000460863113403 0.000132083892822
N=1000: 0.0122890472412 0.00084114074707 0.000464916229248
N=10000: 0.109477043152 0.00530695915222 0.00424313545227
答案 1 :(得分:3)
使用np.exp
,这将以矢量化方式对numpy数组起作用:
>>> def sigmoid(x):
... return 1 / (1 + np.exp(x))
...
>>> sigmoid(scores)
array([ 6.33581776e-01, 3.94391811e-08, 7.68673281e-03])
>>>
你可能不会比这更快。考虑:
>>> def sigmoid(x):
... return 1 / (1 + np.exp(x))
...
和
>>> def sigmoidv(x):
... return 1 / (1 + math.exp(-x))
...
>>> vsigmoid = np.vectorize(sigmoidv)
现在,比较时间。使用小型(100号)阵列:
>>> t = timeit.timeit("vsigmoid(arr)", "from __main__ import vsigmoid, np; arr = np.random.randn(100)", number=100)
>>> t
0.006894525984534994
>>> t = timeit.timeit("sigmoid(arr)", "from __main__ import sigmoid, np; arr = np.random.randn(100)", number=100)
>>> t
0.0007238480029627681
因此,小阵列仍然存在数量级差异。这种性能差异保持相对稳定,具有10,000个大小的阵列:
>>> t = timeit.timeit("vsigmoid(arr)", "from __main__ import vsigmoid, np; arr = np.random.randn(10000)", number=100)
>>> t
0.3823414359940216
>>> t = timeit.timeit("sigmoid(arr)", "from __main__ import sigmoid, np; arr = np.random.randn(10000)", number=100)
>>> t
0.011259705002885312
最后是一个100,000大小的阵列:
>>> t = timeit.timeit("vsigmoid(arr)", "from __main__ import vsigmoid, np; arr = np.random.randn(100000)", number=100)
>>> t
3.7680041620042175
>>> t = timeit.timeit("sigmoid(arr)", "from __main__ import sigmoid, np; arr = np.random.randn(100000)", number=100)
>>> t
0.09544878199812956
答案 2 :(得分:1)
只是澄清apply_along_axis
正在做什么或不做什么。
def sigmoid(x):
print(x) # show the argument
return 1 / (1 + math.exp(-x))
In [313]: np.apply_along_axis(sigmoid, -1,np.array([ -0.54761371 ,17.04850603 ,4.86054302]))
[ -0.54761371 17.04850603 4.86054302] # the whole array
...
TypeError: only length-1 arrays can be converted to Python scalars
您收到错误的原因是apply_along_axis
将整个1d数组传递给您的函数。即轴。对于您的1d数组,这与
sigmoid(np.array([ -0.54761371 ,17.04850603 ,4.86054302]))
apply_along_axis
对你没有任何帮助。
正如其他人所说,切换到np.exp
允许sigmoid
使用数组(使用或不使用apply_along_axis包装器)。
答案 3 :(得分:1)
scipy 已经实现了该功能 幸运的是,Python允许我们在导入时重命名事物:
from scipy.special import expit as sigmoid