Esta es una función logística sigmoidea:
Yo se x. ¿Cómo puedo calcular F (x) en Python ahora?
Digamos x = 0.458.
F (x) =?
Esta es una función logística sigmoidea:
Yo se x. ¿Cómo puedo calcular F (x) en Python ahora?
Digamos x = 0.458.
F (x) =?
Respuestas:
Esto debería hacerlo:
import math
def sigmoid(x):
return 1 / (1 + math.exp(-x))
Y ahora puedes probarlo llamando:
>>> 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 ni se sabe que sea una implementación numéricamente sólida. Si sabe que necesita una implementación muy sólida, estoy seguro de que hay otros en los que la gente realmente ha pensado en este problema.
math.exp
con np.exp
no obtendrá NaNs, aunque recibirá advertencias de tiempo de ejecución.
math.exp
con matriz numpy puede producir algunos errores, como: TypeError: only length-1 arrays can be converted to Python scalars
. Para evitarlo debes usarlo numpy.exp
.
x = max(-709,x)
antes de la expresión?
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 un contenedor costoso (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 preocupan las actuaciones, continúe leyendo, de lo contrario, solo use expit
.
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 esperaba logistic.cdf
es (mucho) más lento que expit
. expit
sigue siendo más lenta que la sigmoid
función 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 sobrecarga de llamadas. Esta sobrecarga es mayor que la velocidad de cálculo deexpit
dada por su naturaleza compilada cuando se llama con un solo valor. Pero se vuelve insignificante cuando se trata de grandes matrices:
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 solo tiene un 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 precalculada de la función sigmoidea que retiene la RAM y cambiar cierta precisión y memoria por cierta velocidad (por ejemplo: http://radimrehurek.com/2013/09 / word2vec-in-python-part-two-optimizing / )
Además, tenga en cuenta que la expit
implementación 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)))
max_q
y rebased_q
por tau
? porque lo intenté y no obtengo probabilidades que sumen 1
q
) por su temperatura. rebased_q puede ser cualquier cosa: no cambia la respuesta; Mejora la estabilidad numérica.
nat_to_exp
es equivalente a softmax (como mencionaste en tu otra respuesta)? Copiar y pegar devuelve probabilidades que no suman 1
de otra manera
>>> def sigmoid(x):
... return 1 /(1+(math.e**-x))
...
>>> sigmoid(0.458)
pow
a menudo se implementa en términos de exp
y log
, por lo que usarlo exp
directamente es casi seguro que sea mejor.
x
es muy negativo.
Otra forma al transformar la tanh
función:
sigmoid = lambda x: .5 * (math.tanh(.5 * x) + 1)
Creo que muchos podrían estar interesados en parámetros libres para alterar la forma de la función sigmoidea. En segundo lugar, para muchas aplicaciones, desea utilizar una función sigmoidea reflejada. En tercer lugar, es posible que desee hacer 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*(x-a)))
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)
Buena respuesta de @unwind. Sin embargo, no puede manejar un número negativo extremo (arrojando 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 sigmoid
función:
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 sigmoidea 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)
Un trazador de líneas ...
In[1]: import numpy as np
In[2]: sigmoid=lambda x: 1 / (1 + np.exp(-x))
In[3]: sigmoid(3)
Out[3]: 0.9525741268224334
pandas DataFrame/Series
o numpy array
:Las principales respuestas son métodos optimizados para el cálculo de un solo punto, pero cuando desea aplicar estos métodos a una serie de pandas o matriz numpy, requiere apply
, que es básicamente un bucle en el fondo e iterará sobre cada fila y aplicará el método. Esto es bastante ineficiente.
Para acelerar nuestro código, podemos hacer uso de la vectorización y la transmisión entumecida:
x = np.arange(-5,5)
np.divide(1, 1+np.exp(-x))
0 0.006693
1 0.017986
2 0.047426
3 0.119203
4 0.268941
5 0.500000
6 0.731059
7 0.880797
8 0.952574
9 0.982014
dtype: float64
O con un pandas Series
:
x = pd.Series(np.arange(-5,5))
np.divide(1, 1+np.exp(-x))
puedes calcularlo como:
import math
def sigmoid(x):
return 1 / (1 + math.exp(-x))
o conceptual, más profundo y sin ninguna importación:
def sigmoid(x):
return 1 / (1 + 2.718281828 ** -x)
o puedes usar numpy para matrices:
import numpy as np #make sure numpy is already installed
def sigmoid(x):
return 1 / (1 + np.exp(-x))
import numpy as np
def sigmoid(x):
s = 1 / (1 + np.exp(-x))
return s
result = sigmoid(0.467)
print(result)
El código anterior es la función sigmoidea logística en python. Si sé que x = 0.467
, la función sigmoide, F(x) = 0.385
. Puede intentar sustituir cualquier valor de x que conozca en el código anterior, y obtendrá un valor diferente de F(x)
.
sigmoid = lambda x: 1 / (1 + math.exp(-x))