Hoe bereken je een logistieke sigmoid-functie in Python?

Dit is een logistieke sigmoid-functie:

Ik weet x. Hoe kan ik nu F(x) in Python berekenen?

Laten we zeggen x = 0,458.

F(x) = ?


Antwoord 1, autoriteit 100%

Dit zou het moeten doen:

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

En nu kun je het testen door te bellen:

>>> sigmoid(0.458)
0.61253961344091512

Update: Merk op dat het bovenstaande voornamelijk bedoeld was als een rechtstreekse één-op-één vertaling van de gegeven uitdrukking in Python-code. Het is nietgetest of bekend als een numeriek verantwoorde implementatie. Als je weet dat je een zeer robuuste implementatie nodig hebt, weet ik zeker dat er anderen zijn waar mensen echt over dit probleem hebben nagedacht.


Antwoord 2, autoriteit 86%

Het is ook beschikbaar in 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

wat alleen een kostbare verpakking is (omdat je de logistieke functie kunt schalen en vertalen) van een andere scipy-functie:

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

Als je je zorgen maakt over optredens, lees dan verder, gebruik anders gewoon expit.

Enkele benchmarking:

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

Zoals verwacht is logistic.cdf(veel) langzamer dan expit. expitis nog steeds langzamer dan de python sigmoid-functie wanneer deze wordt aangeroepen met een enkele waarde, omdat het een universele functie is die is geschreven in C ( http://docs.scipy.org/doc/numpy/reference/ufuncs.html) en heeft dus een oproepoverhead . Deze overhead is groter dan de rekensnelheid van expitgegeven door het gecompileerde karakter wanneer het wordt aangeroepen met een enkele waarde. Maar het wordt verwaarloosbaar als het gaat om grote arrays:

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

(Je zult de kleine verandering opmerken van math.expnaar np.exp(de eerste ondersteunt geen arrays, maar is veel sneller als je alleen één waarde om te berekenen))

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

Maar wanneer u echt prestaties nodig heeft, is een gemeenschappelijke praktijk om een ​​precomputed tabel van de Sigmoïde functie te hebben die in RAM vasthoudt, en een precisie en geheugen inruilen voor wat snelheid (bijvoorbeeld: http://radimreurek.com/2013/09/Word2VEC-IN-PYTHON-PART-TWO- optimaliseren / )

Merk ook op dat expitimplementatie is numeriek stabiel sinds versie 0.14.0: https://github.com/scipy/scipy/issues/3385


3, Autoriteit 19%

Hier is hoe u de logistieke sigmoïde op een numeriek stabiele manier zou implementeren (zoals beschreven hier ):

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)

of misschien is dit nauwkeuriger:

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

Intern, het implementeert dezelfde voorwaarde als hierboven, maar gebruikt dan log1p.

In het algemeen is de multinomiale logistieke sigmoïde:

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

(Echter, logaddexp.reducekan nauwkeuriger zijn.)


Antwoord 4, autoriteit 4%

Een andere manier door de functie tanhte transformeren:

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

Antwoord 5, autoriteit 3%

Ik denk dat velen geïnteresseerd zijn in vrije parameters om de vorm van de sigmoïde functie te veranderen. Ten tweede wilt u voor veel toepassingen een gespiegelde sigmoid-functie gebruiken. Ten derde wilt u misschien een eenvoudige normalisatie uitvoeren, bijvoorbeeld de uitvoerwaarden liggen tussen 0 en 1.

Probeer:

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

En om te tekenen en te vergelijken:

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

Eindelijk:

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


Antwoord 6, autoriteit 3%

op een andere manier

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

Antwoord 7, autoriteit 3%

Gebruik het numpy-pakket om uw sigmoid-functie vectoren te laten ontleden.

In overeenstemming met Deeplearning gebruik ik de volgende code:

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

Antwoord 8

Tensorflow bevat ook een sigmoid-functie:
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

Antwoord 9

Een numeriek stabiele versie van de logistieke sigmoid-functie.

   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)

Antwoord 10

Goed antwoord van @unwind. Het kan echter geen extreem negatief getal aan (overflowError gooien).

Mijn verbetering:

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

11

een voering …

In[1]: import numpy as np
In[2]: sigmoid=lambda x: 1 / (1 + np.exp(-x))
In[3]: sigmoid(3)
Out[3]: 0.9525741268224334

12

Vectorized Methode bij gebruik van pandas DataFrame/Seriesof numpy array:

De bovenste antwoorden zijn geoptimaliseerde methoden voor berekening van één punt, maar wanneer u deze methoden wilt toepassen op een Pandas-serie of Numpy-array, vereist het apply, die in principe voor lus op de achtergrond is zal over elke rij herhalen en de methode toepassen. Dit is vrij inefficiënt.

Om onze code te versnellen, kunnen we gebruik maken van vectoren en numpy omroep:

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

of met een pandas Series:

x = pd.Series(np.arange(-5,5))
np.divide(1, 1+np.exp(-x))

13

U kunt het berekenen als:

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

of conceptueel, dieper en zonder invoer:

def sigmoid(x):
  return 1 / (1 + 2.718281828 ** -x)

of u kunt numpy gebruiken voor matrices:

import numpy as np #make sure numpy is already installed
def sigmoid(x):
  return 1 / (1 + np.exp(-x))

14

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

De bovenstaande code is de logistieke sigmoïde functie in Python.
Als ik weet dat x = 0.467,
De sigmoïde functie, F(x) = 0.385. U kunt proberen elke waarde van x te vervangen die u in de bovenstaande code kent, en u krijgt een andere waarde van F(x).


15

Hieronder staat de Python-functie om hetzelfde te doen.

def sigmoid(x) :
    return 1.0/(1+np.exp(-x))

Other episodes