Esta é uma função sigmóide logística:
Eu sei x. Como posso calcular F (x) em Python agora?
Digamos que x = 0,458.
F (x) =?
Esta é uma função sigmóide logística:
Eu sei x. Como posso calcular F (x) em Python agora?
Digamos que x = 0,458.
F (x) =?
Respostas:
Isso deve servir:
import math
def sigmoid(x):
return 1 / (1 + math.exp(-x))
E agora você pode testá-lo chamando:
>>> sigmoid(0.458)
0.61253961344091512
Atualização : observe que o acima foi destinado principalmente como uma tradução direta direta da expressão fornecida no código Python. É não testados ou conhecido por ser uma boa execução numericamente. Se você sabe que precisa de uma implementação muito robusta, tenho certeza de que há outras em que as pessoas realmente pensaram nesse problema.
math.exp
por np.exp
, não receberá NaNs, embora receba avisos de tempo de execução.
math.exp
com matriz numpy pode produzir alguns erros, como: TypeError: only length-1 arrays can be converted to Python scalars
. Para evitá-lo, você deve usar numpy.exp
.
x = max(-709,x)
antes da expressão?
Também está disponível em 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 é apenas um invólucro caro (porque permite escalar e traduzir a função logística) de outra função ciposa:
In [3]: from scipy.special import expit
In [4]: expit(0.458)
Out[4]: 0.61253961344091512
Se você está preocupado com o desempenho, continue lendo, caso contrário, basta usar 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 esperado, logistic.cdf
é (muito) mais lento que expit
. expit
ainda é mais lento que a sigmoid
função python quando chamada com um único valor, porque é uma função universal escrita em C ( http://docs.scipy.org/doc/numpy/reference/ufuncs.html ) e, portanto, possui uma sobrecarga de chamada. Essa sobrecarga é maior que a aceleração computacional expit
fornecida pela natureza compilada quando chamada com um único valor. Mas isso se torna insignificante quando se trata de grandes matrizes:
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))
....:
(Você notará a pequena alteração de math.exp
para np.exp
(a primeira não suporta matrizes, mas é muito mais rápida se você tiver apenas um 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
Mas quando você realmente precisa de desempenho, uma prática comum é ter uma tabela pré-computada da função sigmoide que contém a RAM e trocar alguma precisão e memória por alguma velocidade (por exemplo: http://radimrehurek.com/2013/09 / word2vec-in-python-parte-dois-otimização / )
Além disso, observe que a expit
implementação é numericamente estável desde a versão 0.14.0: https://github.com/scipy/scipy/issues/3385
Aqui está como você implementaria o sigmóide logístico de uma maneira numericamente estável (como descrito aqui ):
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)
Ou talvez isso seja mais preciso:
import numpy as np
def sigmoid(x):
return math.exp(-np.logaddexp(0, -x))
Internamente, implementa a mesma condição acima, mas depois usa log1p
.
Em geral, o sigmóide logístico multinomial é:
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
e rebased_q
por tau
? porque eu tentei isso e não tenho probabilidades que somam 1
q
) pela sua temperatura. rebased_q pode ser qualquer coisa: não altera a resposta; melhora a estabilidade numérica.
nat_to_exp
tem certeza que é equivalente ao softmax (como você mencionou na sua outra resposta)? Copiar e colar dele retorna probabilidades que não somam 1
outra maneira
>>> def sigmoid(x):
... return 1 /(1+(math.e**-x))
...
>>> sigmoid(0.458)
pow
é frequentemente implementado em termos de exp
e log
, portanto, usar exp
diretamente é quase certamente melhor.
x
é muito negativo.
Outra maneira, transformando a tanh
função:
sigmoid = lambda x: .5 * (math.tanh(.5 * x) + 1)
Sinto que muitos podem estar interessados em parâmetros livres para alterar a forma da função sigmóide. Segundo, para muitos aplicativos que você deseja usar uma função sigmóide espelhada. Terceiro, você pode querer fazer uma normalização simples, por exemplo, os valores de saída estão entre 0 e 1.
Experimentar:
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
E para desenhar e 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)
Boa resposta de @unwind. No entanto, ele não pode lidar com números negativos extremos (lançando OverflowError).
Minha melhoria:
def sigmoid(x):
try:
res = 1 / (1 + math.exp(-x))
except OverflowError:
res = 0.0
return res
O Tensorflow também inclui uma sigmoid
função:
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
Uma versão numericamente estável da função sigmóide 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)
Um forro ...
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
ou numpy array
:As respostas principais são métodos otimizados para o cálculo de ponto único, mas quando você deseja aplicar esses métodos a uma série de pandas ou matriz numpy, é necessário apply
, que é basicamente o loop em segundo plano e iterará em todas as linhas e aplicará o método. Isso é bastante ineficiente.
Para acelerar nosso código, podemos fazer uso de vetorização e transmissão numpy:
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
Ou com um pandas Series
:
x = pd.Series(np.arange(-5,5))
np.divide(1, 1+np.exp(-x))
você pode calculá-lo como:
import math
def sigmoid(x):
return 1 / (1 + math.exp(-x))
ou conceitual, mais profundo e sem importações:
def sigmoid(x):
return 1 / (1 + 2.718281828 ** -x)
ou você pode usar numpy para matrizes:
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)
O código acima é a função sigmóide logística em python. Se eu sei disso x = 0.467
, a função sigmóide F(x) = 0.385
,. Você pode tentar substituir qualquer valor de x que você conhece no código acima e obterá um valor diferente de F(x)
.
sigmoid = lambda x: 1 / (1 + math.exp(-x))