Це логістична сигмоїдна функція:
Я знаю х. Як я можу зараз обчислити F (x) у Python?
Скажімо, x = 0,458.
F (x) =?
Це логістична сигмоїдна функція:
Я знаю х. Як я можу зараз обчислити F (x) у Python?
Скажімо, x = 0,458.
F (x) =?
Відповіді:
Це слід зробити:
import math
def sigmoid(x):
return 1 / (1 + math.exp(-x))
А тепер ви можете протестувати, зателефонувавши:
>>> sigmoid(0.458)
0.61253961344091512
Оновлення : Зауважте, що вищезгадане в основному було задумано як прямий переклад даного виразу в код Python. Він не перевірений і не відомий як чисельно обгрунтований варіант. Якщо ви знаєте, що вам потрібна дуже надійна реалізація, я впевнений, що є й інші, де люди насправді задумалися над цією проблемою.
math.exp
з np.exp
вами не отримаєте нехтує малий, хоча ви будете отримувати попередження у час виконання.
math.exp
з Numpy масиву може дати деякі помилки, наприклад: TypeError: only length-1 arrays can be converted to Python scalars
. Щоб уникнути цього, вам слід скористатися numpy.exp
.
x = max(-709,x)
перед виразом?
Він також доступний у 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
що є лише дорогою обгорткою (оскільки дозволяє масштабувати та перекладати логістичну функцію) іншої функції scipy:
In [3]: from scipy.special import expit
In [4]: expit(0.458)
Out[4]: 0.61253961344091512
Якщо вас турбують виступи, продовжуйте читати, інакше просто використовуйте 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
Як і слід було очікувати logistic.cdf
це (багато) повільніше , ніж expit
. expit
все ще повільніше, ніж sigmoid
функція python, коли її викликають з одним значенням, оскільки це універсальна функція, написана на C ( http://docs.scipy.org/doc/numpy/reference/ufuncs.html ) і, таким чином, має накладні виклики. Цей накладний більший, ніж швидкість обчислення, що expit
задається за складеним характером, коли викликається одним значенням. Але це стає незначним, якщо мова йде про великі масиви:
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))
....:
(Ви помітите невелику зміну з math.exp
на np.exp
(перший не підтримує масиви, але набагато швидше, якщо у вас є лише одне значення для обчислення))
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
Але коли вам справді потрібна продуктивність, поширена практика - мати попередньо обчислену таблицю сигмоїдної функції, яка зберігається в оперативній пам'яті, і торгувати деякою точністю і пам’яттю з деякою швидкістю (наприклад: http://radimrehurek.com/2013/09 / word2vec-in-python-part-two-optimization / )
Також зауважте, що expit
з версії 0.14.0 реалізація чисельно стабільна: https://github.com/scipy/scipy/isissue/3385
Ось як можна було б реалізувати логістичну сигмоїду чисельно стабільним чином (як описано тут ):
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)
А може, це точніше:
import numpy as np
def sigmoid(x):
return math.exp(-np.logaddexp(0, -x))
Внутрішньо він реалізує ту саму умову, що і вище, але потім використовує log1p
.
Загалом, багаточленна логістична сигмоїда є:
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
і rebased_q
по tau
? тому що я спробував це, і я не отримую ймовірності, що дорівнюють 1
q
) на свою температуру. rebased_q може бути будь-яким: він не змінює відповідь; це покращує числову стійкість.
nat_to_exp
це еквівалент softmax (як ви згадували в іншій своїй відповіді)? Копіювати-вставляти його повертає ймовірності, які не дорівнюють 1
Інший спосіб
>>> def sigmoid(x):
... return 1 /(1+(math.e**-x))
...
>>> sigmoid(0.458)
pow
часто реалізується з точки зору exp
та log
, тому exp
безпосередньо використовувати майже напевно краще.
x
це дуже негативно.
Ще один спосіб перетворення tanh
функції:
sigmoid = lambda x: .5 * (math.tanh(.5 * x) + 1)
Я думаю, що багатьох можуть зацікавити вільні параметри для зміни форми сигмоїдної функції. По-друге, для багатьох застосувань потрібно використовувати дзеркальну сигмоподібну функцію. По-третє, ви можете зробити просту нормалізацію, наприклад, вихідні значення між 0 і 1.
Спробуйте:
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
І намалювати та порівняти:
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
Нарешті:
x = np.linspace(0,1,100)
Travel_function = draw_function_on_2x2_grid(x)
Гарна відповідь від @unwind. Однак він не може впоратися з крайньо негативним числом (кидання OverflowError).
Моє поліпшення:
def sigmoid(x):
try:
res = 1 / (1 + math.exp(-x))
except OverflowError:
res = 0.0
return res
Tensorflow включає також 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
Чисельно стабільна версія логістичної сигмоїдної функції.
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)
Один лайнер ...
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
або numpy array
:Верхні відповіді - це оптимізовані методи для обчислення одиничних точок, але коли ви хочете застосувати ці методи до серії панд або масиву numpy, він вимагає apply
, що в основному є циклом у фоновому режимі і буде повторюватись у кожному рядку та застосовувати метод. Це досить неефективно.
Щоб пришвидшити наш код, ми можемо скористатись векторизацією та нумерованим мовленням:
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
Або з pandas Series
:
x = pd.Series(np.arange(-5,5))
np.divide(1, 1+np.exp(-x))
Ви можете обчислити його як:
import math
def sigmoid(x):
return 1 / (1 + math.exp(-x))
або концептуальні, глибші та без жодного імпорту:
def sigmoid(x):
return 1 / (1 + 2.718281828 ** -x)
або ви можете використовувати numpy для матриць:
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)
Вищевказаний код - це логістична сигмоїдна функція в python. Якщо я знаю , що x = 0.467
, сигмовидної функція F(x) = 0.385
. Ви можете спробувати замінити будь-яке значення x, яке ви знаєте, у наведеному вище коді, і ви отримаєте інше значення F(x)
.
sigmoid = lambda x: 1 / (1 + math.exp(-x))