如何在Python中计算逻辑S形函数?

如何在Python中计算逻辑S形函数?,python,sigmoid,Python,Sigmoid,这是逻辑S形函数: In [3]: from scipy.special import expit In [4]: expit(0.458) Out[4]: 0.61253961344091512 我知道x。现在如何在Python中计算F(x) 假设x=0.458 F(x)=?这应该可以做到: import math def sigmoid(x): return 1 / (1 + math.exp(-x)) 现在您可以通过调用以下命令进行测试: >>> sigmo

这是逻辑S形函数:

In [3]: from scipy.special import expit

In [4]: expit(0.458)
Out[4]: 0.61253961344091512

我知道x。现在如何在Python中计算F(x)

假设x=0.458

F(x)=?

这应该可以做到:

import math

def sigmoid(x):
  return 1 / (1 + math.exp(-x))
现在您可以通过调用以下命令进行测试:

>>> sigmoid(0.458)
0.61253961344091512
更新:请注意,上述内容主要是将给定表达式直接一对一地转换为Python代码。它未经测试,也未被认为是数字上可靠的实现。如果您知道您需要一个非常健壮的实现,我相信还有其他人确实考虑过这个问题。

另一种方法

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

它也可以在scipy中获得:

这只是另一个scipy函数的昂贵包装(因为它允许您扩展和转换逻辑函数):

In [3]: from scipy.special import expit

In [4]: expit(0.458)
Out[4]: 0.61253961344091512
如果您关心性能,请继续阅读,否则请使用。

一些基准: 正如预期的那样,
logistic.cdf
expit
慢(很多)
expit
在使用单个值调用时仍然比python
sigmoid
函数慢,因为它是用C()编写的通用函数,因此具有调用开销。当使用单个值调用时,此开销大于
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
的微小变化(第一个不支持数组,但如果您只需要计算一个值,则速度要快得多))

但当您确实需要性能时,通常的做法是在RAM中保存一个sigmoid函数的预计算表,并用一些精度和内存换取一些速度(例如:)


另外,请注意,
expit
自0.14.0版以来,实现在数值上是稳定的:

以下是如何以数值稳定的方式实现逻辑s形图(如所述):

或许这更准确:

import numpy as np

def sigmoid(x):  
    return np.exp(-np.logaddexp(0, -x))
在内部,它实现与上面相同的条件,但随后使用
log1p

一般来说,多项式逻辑S形是:

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

来自@unwind的回答很好。然而,它不能处理极端负数(抛出溢出错误)

我的进步:

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

转换
tanh
函数的另一种方法:

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

我觉得很多人可能对改变sigmoid函数形状的自由参数感兴趣。其次,对于许多应用程序,您希望使用镜像的sigmoid函数。第三,您可能需要进行简单的规范化,例如,输出值介于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)

Tensorflow还包括一个
sigmoid
功能:


logistic-sigmoid函数的数值稳定版本

    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)
def sigmoid(x):
位置掩码=(x>=0)
负屏蔽=(x<0)
z=np.类零(x,dtype=float)
z[pos\u mask]=np.exp(-x[pos\u mask])
z[neg_mask]=np.exp(x[neg_mask])
top=np.one_like(x,dtype=float)
顶部[neg_mask]=z[neg_mask]
返回顶部/(1+z)

使用numpy包允许您的sigmoid函数解析向量

根据Deeplearning,我使用以下代码:

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

In[1]: import numpy as np

In[2]: sigmoid=lambda x: 1 / (1 + np.exp(-x))

In[3]: sigmoid(3)
Out[3]: 0.9525741268224334
上面的代码是python中的logistic sigmoid函数。 如果我知道
x=0.467
, S形函数,
F(x)=0.385
。您可以尝试替换上述代码中已知的任何x值,当使用
pandas DataFrame/Series
numpy array
时,您将获得不同的
F(x)

矢量化方法: 最重要的答案是针对单点计算的优化方法,但当您想将这些方法应用于pandas系列或numpy阵列时,它需要
apply
,这基本上是用于后台循环,并将迭代每一行并应用该方法。这是相当低效的

为了加快代码速度,我们可以使用矢量化和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
或使用熊猫系列:

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

下面是执行相同操作的python函数

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

此功能和展开功能之间有什么区别?math.e**-x比math.exp(-x)好吗?在输出结果方面没有区别。如果您想知道速度方面的差异,可以使用timeit来计时它们的执行时间。但这并不重要。
pow
通常是根据
exp
log
实现的,因此直接使用
exp
几乎肯定会更好。当
x
非常负时,会出现溢出。因为我经常需要它来尝试一些小事情:
sigmoid=lambda x:1/(1+math.exp(-x))
这不适用于x的极端负值。我一直在使用这个不幸的实现,直到我注意到它正在创建NAN。如果将
math.exp
替换为
np.exp
,则不会得到NAN,尽管会得到运行时警告。将
math.exp
与numpy数组一起使用可能会产生一些错误,例如:
TypeError:只有长度为1的数组才能转换为Python标量。为了避免这种情况,您应该使用
numpy.exp
。只需在表达式之前添加
x=max(-709,x)
就可以减轻数值不稳定性吗?这样更好,但您仍然会遇到负值的数值冲击问题。使用浮点(1.)而不是整数(1)在你的sigmoid函数中,你可以减少10%的运行时间。我不确定我是否理解你的意思(示例中使用了浮点),但在任何情况下,很少计算整数上的sigmoid。kd88的意思是,你在函数(1)中使用的数字文字被解析为整数,
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
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)
import numpy as np #make sure numpy is already installed
def sigmoid(x):
  return 1 / (1 + np.exp(-x))
def sigmoid(x) :
    return 1.0/(1+np.exp(-x))