Python 沿 numpy 数组应用函数
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/43024745/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Applying a function along a numpy array
提问by Melissa Stewart
I've the following numpy ndarray.
我有以下 numpy ndarray。
[ -0.54761371 17.04850603 4.86054302]
I want to apply this function to all elements of the array
我想将此函数应用于数组的所有元素
def sigmoid(x):
return 1 / (1 + math.exp(-x))
probabilities = np.apply_along_axis(sigmoid, -1, scores)
This is the error that I get.
这是我得到的错误。
TypeError: only length-1 arrays can be converted to Python scalars
What am I doing wrong.
我究竟做错了什么。
回答by Serenity
Function numpy.apply_along_axis
is not good for this purpose.
Try to use numpy.vectorize
to vectorize your function: https://docs.scipy.org/doc/numpy/reference/generated/numpy.vectorize.htmlThis function defines a vectorized function which takes a nested sequence of objects or numpy arrays as inputs and returns an single or tuple of numpy array as output.
函数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)
Output: [ 0.36641822 0.99999996 0.99231327]
输出: [ 0.36641822 0.99999996 0.99231327]
Performance test which shows that the scipy.special.expit
is the best solution to calculate logistic function and vectorized variant comes to the worst:
性能测试表明,这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)
Results:
结果:
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
回答by juanpa.arrivillaga
Use np.exp
and that will work on numpy arrays in a vectorized fashion:
使用np.exp
and 将以矢量化方式处理 numpy 数组:
>>> def sigmoid(x):
... return 1 / (1 + np.exp(-x))
...
>>> sigmoid(scores)
array([ 6.33581776e-01, 3.94391811e-08, 7.68673281e-03])
>>>
You will likely not get any faster than this. Consider:
您可能不会比这更快。考虑:
>>> def sigmoid(x):
... return 1 / (1 + np.exp(-x))
...
And:
和:
>>> def sigmoidv(x):
... return 1 / (1 + math.exp(-x))
...
>>> vsigmoid = np.vectorize(sigmoidv)
Now, to compare the timings. With a small (size 100) array:
现在,比较时间。使用小(大小 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
So, still an order-of-magnitude difference with small arrays. This performance differences stays relatively constant, with a 10,000 size array:
因此,与小阵列仍然存在数量级差异。这种性能差异保持相对恒定,数组大小为 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
And finally with a size 100,000 array:
最后是一个大小为 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
回答by hpaulj
Just to clarify what apply_along_axis
is doing, or not doing.
只是为了澄清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
The reason you get the error is that apply_along_axis
passes a whole 1d array to your function. I.e. the axis. For your 1d array this is the same as
您收到错误的原因是apply_along_axis
将整个一维数组传递给您的函数。即轴。对于您的一维数组,这与
sigmoid(np.array([ -0.54761371 ,17.04850603 ,4.86054302]))
The apply_along_axis
does nothing for you.
在apply_along_axis
你什么也不做。
As others noted,switching to np.exp
allows sigmoid
to work with the array (with or without the apply_along_axis wrapper).
正如其他人指出的那样,切换到np.exp
允许sigmoid
使用数组(使用或不使用 apply_along_axis 包装器)。
回答by Sergey V.
scipyalready implements the function Luckily, Python allows us to rename things upon import:
scipy已经实现了这个函数 幸运的是,Python 允许我们在导入时重命名:
from scipy.special import expit as sigmoid