【发布时间】: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 --> 0是y应该去∞?和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