【问题标题】:sigmoidal regression with scipy, numpy, python, etcscipy、numpy、python等的sigmoidal回归
【发布时间】:2011-05-17 12:41:05
【问题描述】:

我有两个变量(x 和 y),它们之间的关系有点像 sigmoid,我需要找到某种预测方程,让我能够在给定 x 的任何值的情况下预测 y 的值。我的预测方程需要显示两个变量之间的某种 S 型关系。因此,我不能满足于产生一条直线的线性回归方程。我需要看到两个变量图的左右两侧出现的斜率逐渐的曲线变化。

在谷歌搜索曲线回归和 python 之后,我开始使用 numpy.polyfit,但这给了我可怕的结果,如果你运行下面的代码,你可以看到。 谁能告诉我如何重写下面的代码以获得我想要的 sigmoidal 回归方程的类型?

如果你运行下面的代码,你可以看到它给出了一个向下的抛物线,这不是我的变量之间的关系应该是这样的。相反,我的两个变量之间应该有更多的 S 型关系,但与我在下面的代码中使用的数据紧密匹配。下面代码中的数据是来自大样本研究的平均值,因此它们的统计能力比它们的五个数据点可能暗示的要大。我没有来自大样本研究的实际数据,但我确实有以下方法及其标准偏差(我没有显示)。我宁愿只用下面列出的平均数据绘制一个简单的函数,但如果复杂性能带来实质性的改进,代码可能会变得更复杂。

如何更改我的代码以显示最适合的 sigmoidal 函数,最好使用 scipy、numpy 和 python?这是我的代码的当前版本,需要修复:

import numpy as np
import matplotlib.pyplot as plt

# Create numpy data arrays
x = np.array([821,576,473,377,326])
y = np.array([255,235,208,166,157])

# Use polyfit and poly1d to create the regression equation
z = np.polyfit(x, y, 3)
p = np.poly1d(z)
xp = np.linspace(100, 1600, 1500)
pxp=p(xp)

# Plot the results
plt.plot(x, y, '.', xp, pxp, '-')
plt.ylim(140,310)
plt.xlabel('x')
plt.ylabel('y')
plt.grid(True)
plt.show()

在下面编辑:(重新提出问题)

您的反应及其速度令人印象深刻。谢谢你,unutbu。 但是,为了产生更有效的结果,我需要重新构建我的数据值。这意味着将 x 值重新转换为最大 x 值的百分比,同时将 y 值重新转换为原始数据中 x 值的百分比。我试图用你的代码来做这件事,并想出了以下内容:

import numpy as np 
import matplotlib.pyplot as plt 
import scipy.optimize 

# Create numpy data arrays 
'''
# Comment out original data
#x = np.array([821,576,473,377,326]) 
#y = np.array([255,235,208,166,157]) 
'''

# Re-calculate x values as a percentage of the first (maximum)
# original x value above
x = np.array([1.000,0.702,0.576,0.459,0.397])

# Recalculate y values as a percentage of their respective x values
# from original data above
y = np.array([0.311,0.408,0.440,0.440,0.482])

def sigmoid(p,x): 
    x0,y0,c,k=p 
    y = c / (1 + np.exp(-k*(x-x0))) + y0 
    return y 

def residuals(p,x,y): 
    return y - sigmoid(p,x) 

p_guess=(600,200,100,0.01) 
(p,  
 cov,  
 infodict,  
 mesg,  
 ier)=scipy.optimize.leastsq(residuals,p_guess,args=(x,y),full_output=1,warning=True)  

'''
# comment out original xp to allow for better scaling of
# new values
#xp = np.linspace(100, 1600, 1500) 
'''

xp = np.linspace(0, 1.1, 1100) 
pxp=sigmoid(p,xp) 

x0,y0,c,k=p 
print('''\ 
x0 = {x0}
y0 = {y0}
c = {c}
k = {k}
'''.format(x0=x0,y0=y0,c=c,k=k)) 

# Plot the results 
plt.plot(x, y, '.', xp, pxp, '-') 
plt.ylim(0,1) 
plt.xlabel('x') 
plt.ylabel('y') 
plt.grid(True) 
plt.show()

你能告诉我如何修复这个修改后的代码吗?
注意:通过重新转换数据,我基本上将 2d (x,y) sigmoid 围绕z 轴旋转 180 度。此外,1.000 并不是 x 值的最大值。相反,1.000 是在最大测试条件下来自不同测试参与者的值范围的平均值。


下面的第二次编辑:

谢谢你,ubuntu。我仔细阅读了您的代码,并在 scipy 文档中查看了它的各个方面。由于您的名字似乎以 scipy 文档的作者身份出现,我希望您能回答以下问题:

1.) leastsq() 调用residuals(),然后返回输入y 向量和sigmoid() 函数返回的y 向量之间的差?如果是这样,它如何解释输入 y-vector 和 sigmoid() 函数返回的 y-vector 长度的差异?

2.) 看起来我可以为任何数学方程调用 leastsq(),只要我通过残差函数访问该数学方程,该残差函数又调用数学函数。这是真的吗?

3.) 另外,我注意到 p_guess 具有与 p 相同数量的元素。这是否意味着p_guess的四个元素分别与x0、y0、c、k返回的值依次对应?

4.) 作为参数发送给residuals() 和sigmoid() 函数的p 是否与将由leastsq() 输出的p 相同,并且leastsq() 函数在返回之前在内部使用该p是吗?

5.) p 和 p_guess 是否可以有任意数量的元素,这取决于用作模型的方程的复杂性,只要 p 中的元素数等于 p_guess 中的元素数?

【问题讨论】:

  • @MedicalMath:我很困惑。因为右边的x --> 0y 应该去?和x --> ∞ 一样,y 会转到-∞ 吗?还是0?我不确定这个新数据应该适合什么功能。
  • 不,我仍然想尝试逻辑回归,只是将 e 的指数符号反转以旋转图形。 (对不起,直到我修改了上面的代码之后我才弄清楚。)该函数仍然有两个水平渐近线。问题是我的代码仍然为最佳拟合线提供了一条平线,我认为问题可能是我看不到您如何获得 p_guess 的值。你能告诉我如何获得 p_guess 的值吗?或者可能存在更深层次的问题。
  • 要拟合的新函数为:y = c / (1 + np.exp(k*(x-x0))) + y0。注意指数符号的变化。
  • @MedicalMath:我认为问题在于转换 x 和 y 后,数据看起来不再像 sigmoid。使用p_guess = (0.5, 0.5, 1, 0.5) 我得到这个:imgur.com/isWB6.png。显然这是错误的,但我无法做得更好。如果您的数据非常适合您的模型,通常任何合理的p_guess 值都可以。 (条条大路通罗马。)但是当数据不能很好地拟合模型时,你会得到一个奇怪的拟合(就像上面的那个)。您确定要将原始 y 除以 x 吗?这会将非常类似于 sigmoid 的数据转换为非常类似于 unsigmoid 的数据。
  • @MedicalMath:如果您需要一个答案,您应该将其标记为“已接受的答案”。

标签: python statistics numpy scipy scientific-computing


【解决方案1】:

正如上面@unutbu 所指出的,scipy 现在提供了scipy.optimize.curve_fit,它拥有一个不太复杂的调用。如果有人想要以这些术语快速了解相同过程的外观,我将在下面提供一个最小示例:

from scipy.optimize import curve_fit

def sigmoid(x, k, x0):

    return 1.0 / (1 + np.exp(-k * (x - x0)))

# Parameters of the true function
n_samples = 1000
true_x0 = 15
true_k = 1.5
sigma = 0.2

# Build the true function and add some noise
x = np.linspace(0, 30, num=n_samples)
y = sigmoid(x, k=true_k, x0=true_x0) 
y_with_noise = y + sigma * np.random.randn(n_samples)

# Sample the data from the real function (this will be your data)
some_points = np.random.choice(1000, size=30)  # take 30 data points
xdata = x[some_points]
ydata = y_with_noise[some_points]

# Fit the curve
popt, pcov = curve_fit(sigmoid, xdata, ydata)
estimated_k, estimated_x0 = popt

# Plot the fitted curve
y_fitted = sigmoid(x, k=estimated_k, x0=estimated_x0)

# Plot everything for illustration
fig = plt.figure()
ax = fig.add_subplot(111)
ax.plot(x, y_fitted, '--', label='fitted')
ax.plot(x, y, '-', label='true')
ax.plot(xdata, ydata, 'o', label='samples')

ax.legend()

这样的结果如下图所示:

【讨论】:

  • 您好,问题:我在您的代码示例中看到了 return_sigmoid,但我看不到它在任何地方定义或在任何地方调用。我的 Spyder 安装也抱怨它。你能告诉我我错过了什么吗?谢谢你。我的 scipy 版本是 0.18.1,numpy 版本是 1.17.2
【解决方案2】:

使用scipy.optimize.leastsq

import numpy as np
import matplotlib.pyplot as plt
import scipy.optimize

def sigmoid(p,x):
    x0,y0,c,k=p
    y = c / (1 + np.exp(-k*(x-x0))) + y0
    return y

def residuals(p,x,y):
    return y - sigmoid(p,x)

def resize(arr,lower=0.0,upper=1.0):
    arr=arr.copy()
    if lower>upper: lower,upper=upper,lower
    arr -= arr.min()
    arr *= (upper-lower)/arr.max()
    arr += lower
    return arr

# raw data
x = np.array([821,576,473,377,326],dtype='float')
y = np.array([255,235,208,166,157],dtype='float')

x=resize(-x,lower=0.3)
y=resize(y,lower=0.3)
print(x)
print(y)
p_guess=(np.median(x),np.median(y),1.0,1.0)
p, cov, infodict, mesg, ier = scipy.optimize.leastsq(
    residuals,p_guess,args=(x,y),full_output=1,warning=True)  

x0,y0,c,k=p
print('''\
x0 = {x0}
y0 = {y0}
c = {c}
k = {k}
'''.format(x0=x0,y0=y0,c=c,k=k))

xp = np.linspace(0, 1.1, 1500)
pxp=sigmoid(p,xp)

# Plot the results
plt.plot(x, y, '.', xp, pxp, '-')
plt.xlabel('x')
plt.ylabel('y',rotation='horizontal') 
plt.grid(True)
plt.show()

产量

带有sigmoid参数

x0 = 0.826964424481
y0 = 0.151506745435
c = 0.848564826467
k = -9.54442292022

请注意,对于较新版本的 scipy(例如 0.9),还有比 leastsq 更易于使用的 scipy.optimize.curve_fit 函数。使用curve_fit 拟合 sigmoid 的相关讨论可以在here 找到。

编辑:添加了resize 函数,以便可以重新缩放和移动原始数据以适合任何所需的边界框。


"你的名字似乎以作家的身份出现 scipy 文档”

免责声明:我不是 scipy 文档的作者。我只是一个用户,而且是个新手。我对leastsq 的了解大部分来自阅读由Travis Oliphant 撰写的this tutorial

1.) leastsq() 调用residuals(),然后返回差值 在输入 y 向量和 sigmoid() 返回的 y 向量 功能?

是的!没错。

如果是这样,它是如何解释的? 输入长度的差异 y 向量和返回的 y 向量 sigmoid() 函数?

长度相同:

In [138]: x
Out[138]: array([821, 576, 473, 377, 326])

In [139]: y
Out[139]: array([255, 235, 208, 166, 157])

In [140]: p=(600,200,100,0.01)

In [141]: sigmoid(p,x)
Out[141]: 
array([ 290.11439268,  244.02863507,  221.92572521,  209.7088641 ,
        206.06539033])

Numpy 的一大优点是它允许您编写对整个数组进行运算的“向量”方程。

y = c / (1 + np.exp(-k*(x-x0))) + y0

可能看起来它适用于浮点数(确实可以),但如果你将 x 设为一个 numpy 数组,并且将 c,k,x0,y0 设为浮点数,则等式定义 @987654340 @ 是一个与x 形状相同的 numpy 数组。所以sigmoid(p,x) 返回一个 numpy 数组。在numpybook 中有更完整的解释它是如何工作的(认真的 numpy 用户需要阅读)。

2.) 看起来我可以为任何数学方程调用 leastsq(),只要我 通过 a 访问该数学方程式 残差函数,这反过来 调用数学函数。这是真的吗?

没错。 leastsq 试图最小化残差(差)的平方和。它搜索参数空间(p 的所有可能值)寻找最小化平方和的p。发送到residualsxy 是您的原始数据值。它们是固定的。他们不会改变。 leastsq 试图最小化的是 ps(sigmoid 函数中的参数)。

3.) 另外,我注意到 p_guess 具有与 p 相同数量的元素。做 这意味着四个要素 p_guess 依次对应, 分别与返回的值 x0,y0,c 和 k?

确实如此!与牛顿法一样,leastsq 需要对p 进行初始猜测。您将其提供为p_guess。当你看到

scipy.optimize.leastsq(residuals,p_guess,args=(x,y))

您可以认为作为第一次传递的最小平方算法(实际上是 Levenburg-Marquardt 算法)的一部分,最小平方调用residuals(p_guess,x,y)。 注意

之间的视觉相似性
(residuals,p_guess,args=(x,y))

residuals(p_guess,x,y)

它可以帮助您记住leastsq 的参数的顺序和含义。

residualssigmoid 一样返回一个 numpy 数组。数组中的值先平方,然后求和。这是要击败的数字。然后p_guess 会随着leastsq 寻找一组最小化residuals(p_guess,x,y) 的值而变化。

4.) 是作为参数发送给residuals() 的p 吗? sigmoid() 函数与 p 相同 将由 leastsq() 输出,并且 leastsq() 函数正在使用该 p 在内部返回之前?

嗯,不完全是。正如您现在所知道的,p_guess 会随着leastsq 搜索使residuals(p,x,y) 最小化的p 值而变化。发送到leastsqp(呃,p_guess)与leastsq 返回的p 具有相同的形状。显然值应该不同,除非你是个猜谜者:)

5.) p 和 p_guess 可以有任意数量的元素,具体取决于 所用方程的复杂性 作为一个模型,只要数量 p 中的元素等于数字 p_guess 中的元素个数?

是的。我没有针对大量参数对leastsq 进行压力测试,但它是一个非常强大的工具。

【讨论】:

    【解决方案3】:

    对于 Python 中的逻辑回归,scikits-learn 公开了高性能拟合代码:

    http://scikit-learn.sourceforge.net/modules/linear_model.html#logistic-regression

    【讨论】:

      【解决方案4】:

      我认为使用任何次数的多项式拟合都不会得到好的结果——因为 对于足够大和足够小的 X,所有多项式都趋于无穷大,但 sigmoid 曲线会在每个方向上渐近地逼近某个有限值。

      我不是 Python 程序员,所以不知道 numpy 是否有更通用的曲线拟合 常规。如果你必须自己动手,也许Logistic regression 上的这篇文章会给你一些想法。

      【讨论】:

      • sigmoid 实际上只是逻辑函数的一个特例。 +1 指出多项式无法解决问题。
      猜你喜欢
      • 1970-01-01
      • 2023-03-05
      • 1970-01-01
      • 1970-01-01
      • 2011-12-08
      • 2018-08-11
      • 1970-01-01
      • 2015-01-21
      • 2020-01-06
      相关资源
      最近更新 更多