¿Cómo calcular una función sigmoidea logística en Python?

Esta es una función sigmoidea logística:

introduzca la descripción de la imagen aquí

Yo se x ¿Cómo puedo calcular F (x) en Python ahora?

Digamos que x = 0.458.

F (x) =?

Esto debería hacerlo:

import math def sigmoid(x): return 1 / (1 + math.exp(-x)) 

Y ahora puedes probarlo llamando al:

 >>> sigmoid(0.458) 0.61253961344091512 

Actualización : Tenga en cuenta que lo anterior fue pensado principalmente como una traducción directa uno a uno de la expresión dada al código Python. No se ha probado o se sabe que es una implementación numéricamente sólida. Si sabe que necesita una implementación muy robusta, estoy seguro de que hay otros en los que la gente realmente ha pensado en este problema.

También está disponible en scipy: http://docs.scipy.org/doc/scipy/reference/generated/scipy.stats.logistic.html

 In [1]: from scipy.stats import logistic In [2]: logistic.cdf(0.458) Out[2]: 0.61253961344091512 

que es solo una envoltura costosa (porque le permite escalar y traducir la función logística) de otra función scipy:

 In [3]: from scipy.special import expit In [4]: expit(0.458) Out[4]: 0.61253961344091512 

Si le preocupa el rendimiento, siga leyendo, de lo contrario, utilice expit .

Algunos puntos de referencia:

 In [5]: def sigmoid(x): ....: return 1 / (1 + math.exp(-x)) ....: In [6]: %timeit -r 1 sigmoid(0.458) 1000000 loops, best of 1: 371 ns per loop In [7]: %timeit -r 1 logistic.cdf(0.458) 10000 loops, best of 1: 72.2 µs per loop In [8]: %timeit -r 1 expit(0.458) 100000 loops, best of 1: 2.98 µs per loop 

Como se espera, logistic.cdf es (mucho) más lento que expit . expit sigue siendo más lento que la función sigmoid python cuando se llama con un solo valor porque es una función universal escrita en C ( http://docs.scipy.org/doc/numpy/reference/ufuncs.html ) y por lo tanto tiene una llamada gastos generales. Esta sobrecarga es mayor que la aceleración del cálculo de la expit dada por su naturaleza comstackda cuando se llama con un solo valor. Pero se vuelve insignificante cuando se trata de grandes arreglos:

 In [9]: import numpy as np In [10]: x = np.random.random(1000000) In [11]: def sigmoid_array(x): ....: return 1 / (1 + np.exp(-x)) ....: 

(Notará el pequeño cambio de math.exp a np.exp (el primero no admite matrices, pero es mucho más rápido si tiene un solo valor para calcular))

 In [12]: %timeit -r 1 -n 100 sigmoid_array(x) 100 loops, best of 1: 34.3 ms per loop In [13]: %timeit -r 1 -n 100 expit(x) 100 loops, best of 1: 31 ms per loop 

Pero cuando realmente necesita rendimiento, una práctica común es tener una tabla precomputada de la función sigmoide que contiene RAM, e intercambiar cierta precisión y memoria por algo de velocidad (por ejemplo: http://radimrehurek.com/2013/09 / word2vec-in-python-part-two-optimizing / )

Además, tenga en cuenta que la implementación de expit es numéricamente estable desde la versión 0.14.0: https://github.com/scipy/scipy/issues/3385

Así es como implementaría el sigmoide logístico de una manera numéricamente estable (como se describe aquí ):

 def sigmoid(x): "Numerically-stable sigmoid function." if x >= 0: z = exp(-x) return 1 / (1 + z) else: z = exp(x) return z / (1 + z) 

O tal vez esto es más preciso:

 import numpy as np def sigmoid(x): return math.exp(-np.logaddexp(0, -x)) 

Internamente, implementa la misma condición que la anterior, pero luego usa log1p .

En general, el sigmoide logístico multinomial es:

 def nat_to_exp(q): max_q = max(0.0, np.max(q)) rebased_q = q - max_q return np.exp(rebased_q - np.logaddexp(-max_q, np.logaddexp.reduce(rebased_q))) 

(Sin embargo, logaddexp.reduce podría ser más preciso).

de otra manera

 >>> def sigmoid(x): ... return 1 /(1+(math.e**-x)) ... >>> sigmoid(0.458) 

Siento que muchos podrían estar interesados ​​en los parámetros libres para alterar la forma de la función sigmoide. En segundo lugar, para muchas aplicaciones desea utilizar una función sigmoide reflejada. En tercer lugar, es posible que desee realizar una normalización simple, por ejemplo, los valores de salida están entre 0 y 1.

Tratar:

 def normalized_sigmoid_fkt(a, b, x): ''' Returns array of a horizontal mirrored normalized sigmoid function output between 0 and 1 Function parameters a = center; b = width ''' s= 1/(1+np.exp(b*(xa))) return 1*(s-min(s))/(max(s)-min(s)) # normalize function to 0-1 

Y para dibujar y comparar:

 def draw_function_on_2x2_grid(x): fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2) plt.subplots_adjust(wspace=.5) plt.subplots_adjust(hspace=.5) ax1.plot(x, normalized_sigmoid_fkt( .5, 18, x)) ax1.set_title('1') ax2.plot(x, normalized_sigmoid_fkt(0.518, 10.549, x)) ax2.set_title('2') ax3.plot(x, normalized_sigmoid_fkt( .7, 11, x)) ax3.set_title('3') ax4.plot(x, normalized_sigmoid_fkt( .2, 14, x)) ax4.set_title('4') plt.suptitle('Different normalized (sigmoid) function',size=10 ) return fig 

Finalmente:

 x = np.linspace(0,1,100) Travel_function = draw_function_on_2x2_grid(x) 

Gráfico de funciones sigmoideas

Otra forma transformando la función tanh :

 sigmoid = lambda x: .5 * (math.tanh(.5 * x) + 1) 

Utilice el paquete numpy para permitir que su función sigmoide analice vectores.

De conformidad con Deeplearning, utilizo el siguiente código:

 import numpy as np def sigmoid(x): s = 1/(1+np.exp(-x)) return s 

Buena respuesta de @unwind. Sin embargo, no puede manejar números negativos extremos (lanzar OverflowError).

Mi mejora:

 def sigmoid(x): try: res = 1 / (1 + math.exp(-x)) except OverflowError: res = 0.0 return res 

Tensorflow también incluye una función sigmoid : https://www.tensorflow.org/versions/r1.2/api_docs/python/tf/sigmoid

 import tensorflow as tf sess = tf.InteractiveSession() x = 0.458 y = tf.sigmoid(x) u = y.eval() print(u) # 0.6125396 

Una versión numéricamente estable de la función sigmoide logística.

  def sigmoid(x): pos_mask = (x >= 0) neg_mask = (x < 0) z = np.zeros_like(x,dtype=float) z[pos_mask] = np.exp(-x[pos_mask]) z[neg_mask] = np.exp(x[neg_mask]) top = np.ones_like(x,dtype=float) top[neg_mask] = z[neg_mask] return top / (1 + z)