Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Applying a function along a numpy array

Tags:

I've the following 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.

like image 801
Melissa Stewart Avatar asked Mar 26 '17 03:03

Melissa Stewart


People also ask

How do you add a function to an array in Python?

If you are using List as an array, you can use its append(), insert(), and extend() functions. You can read more about it at Python add to List. If you are using array module, you can use the concatenation using the + operator, append(), insert(), and extend() functions to add elements to the array.

Is there a map function in NumPy?

Map a Function in NumPy With the numpy. vectorize() function maps functions on data structures that contain a sequence of objects like arrays in Python. It successively applies the input function on each element of the sequence or array.

How do I create a function in NumPy?

To create you own ufunc, you have to define a function, like you do with normal functions in Python, then you add it to your NumPy ufunc library with the frompyfunc() method. The frompyfunc() method takes the following arguments: function - the name of the function. inputs - the number of input arguments (arrays).

Can I use += with NumPy?

In numpy, += is implemented to do in memory changes, while + returns a new array.


2 Answers

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.html This 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.

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]

Performance test which shows that the scipy.special.expit is the best solution to calculate logistic function and vectorized variant comes to the worst:

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 
like image 51
Serenity Avatar answered Sep 22 '22 09:09

Serenity


Use np.exp and that will work on numpy arrays in a vectorized fashion:

>>> 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:

>>> 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:

>>> 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:

>>> 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 
like image 31
juanpa.arrivillaga Avatar answered Sep 21 '22 09:09

juanpa.arrivillaga