【问题标题】:Parameters of a sigmoid regression in Python + scipyPython + scipy中sigmoid回归的参数
【发布时间】:2014-09-09 15:41:47
【问题描述】:

我有一个 Python 数组,其中包含 日期,表示某一现象在特定年份的发生次数。该向量包含 200 个不同的日期,每个日期重复一定次数。重复是现象发生的次数。我设法使用以下代码 sn-p 计算并绘制了 matplotlib 的累积和:

counts = arange(0, len(list_of_dates))
# Add the cumulative sum to the plot (list_of_dates contains repetitions)
plt.plot(list_of_dates, counts, linewidth=3.0)   

蓝色表示累积和的曲线,其他颜色表示我想获得的参数。但是,我需要蓝色曲线的数学表示才能获得这些参数。我知道这种类型的曲线可以使用逻辑回归进行调整,但是我不明白如何在 Python 中做到这一点。

  1. 首先我尝试使用来自 Scikit-learn 的 LogisticRegression,但后来我意识到他们似乎正在使用此模型进行机器学习 classification(和其他类似的东西),不是/strong> 我想要什么。

  2. 然后我想我可以直接进入逻辑函数的定义,并尝试自己构建它。我找到了this thread,建议使用scipy.special.expit 来计算曲线。看来这个功能已经实现了,所以我决定使用它。所以我这样做了:

    target_vector = dictionary.values() Y = expit(target_vector) plt.plot(list_of_dates, y, linewidth=3.0)

我得到了一个包含 209 个元素(与 target_vector 相同)的向量,如下所示:[ 1. 0.98201379 0.95257413 0.73105858 ... 0.98201379 1. ]。然而,图形输出看起来就像一个孩子在抓纸,而不是像图片中那样漂亮的 sigmoid 曲线。

我还检查了其他 Stack Overflow 线程(this、this),但与它们相比,我想我需要做的只是一个玩具示例。我只需要数学公式来计算一些快速简单的参数。

有没有办法做到这一点并获得 sigmoidal 函数的数学表示?

非常感谢!

【问题讨论】:

  • 逻辑回归确实是一个分类问题。我认为您正在寻找具有 logit 链接函数的广义线性模型。我从来没有在 python 中这样做过,但statsmodels 为 GLM 提供了许多不同链接功能的实现。我很确定你也会在那里找到一个 logit 回归模型。
  • 我一直在检查您在逻辑回归类别中提到的包,据我(可怜的)知识,似乎更倾向于“机器学习分类”问题,而不是“曲线拟合”问题,到目前为止,我认为这是我需要的:曲线的数学描述。也许我在最初的帖子中滥用了这些条款。 :)

标签: python numpy matplotlib scipy logistic-regression


【解决方案1】:

您提到的情节可能看起来很糟糕有几个原因。

第一个是因为dictionary.values() 以未排序的顺序返回值。如果你这样做会发生什么(未经测试,因为我没有你的字典):

target_pairs = sorted(dictionary.iteritems()) #should be a sorted list of (date, count)
target_vector = [count for (date, count) in target_pairs]

并查看生成的target_vector?现在应该会增加。

从那里到一个逻辑函数需要更多的工作:你需要规范化target_vector,使值位于 [0, 1],然后应用 scipy.special.logit(这会在 [0, 1 上打开一个 sigmoid ] 成一条直线),然后您可以找到最适合该直线的直线。然后你可以恢复你的逻辑模型的参数:

y = C * sigmoid(m*x + b)

m 和 b 是转换后数据的线性回归的斜率和截距,C 是对数据进行归一化时除以的值。

【讨论】:

  • 您指出了一个非常重要的细节:订单。事实上,我没有考虑到这一点,所以我根据你的建议修改了我的代码。我也不知道需要对 Y 轴数据进行归一化,但这很有意义,所以我做到了。但是,我不清楚如何获得逻辑模型的参数(斜率、截距和这个除数)。我正在新帖子中更新我目前的情况。谢谢!
  • 哦,好的,您使用了curve_fit,这是一种与我预期不同的方法,但可能会更好。 popt 的值将是数组[x0, k],它使sigmoid(x[i], x0, k) 尽可能接近y[i]——所以这是 sigmoid 曲线的两个参数。 (标准的 sigmoid 曲线虽然返回 [0,1] 中的数字 - 因此要恢复原始数据,您需要将其乘以除以进行归一化的任何值。WRT 归一化,关键是缩放您的数据,以使最小值为 0,最大值为 1——即,将y 除以y.max()。这是你做的吗?)
  • 好的,所以我知道 x0 是斜率,k 是截距。这两个是最符合我的数据的曲线特征。这个说法正确吗? :-) 关于规范化,我添加了一些代码行,以便您了解我是如何执行该操作的。我觉得自己开始做优化有点懒(T_T),我发现 sklearn.preprocessing.normalize 函数显然可以解决问题。所以我没有故意划分,但我不得不缩放我的值,因为它们对于“curve_fit”来说太小了。你怎么看?是否有意义?非常感谢!
  • 我试图在一个点中找到 y(x) 的值。为此,我将“popt”中返回的值放入函数中。像这样:y(100) = sigmoid(100, 8.56332788e+01, 6.53678132e-02)。但是,这将返回 y(100) = 0.9974。根据情节,这不是真的。同样,y(50) = 0.9375,这也不正确。为什么结果发生了变化,但曲线看起来不错?谢谢
【解决方案2】:

使用this post和昨天发布的cmets,我想出了以下代码:

from scipy.optimize import curve_fit
import matplotlib.pyplot as plt
import numpy as np
from sklearn.preprocessing import normalize # Added this new line

# This is how I normalized the vector. "ydata" looked like this:
# original_ ydata = [ 1, 3, 8, 14, 12, 27, 33, 36, 87, 136, 77, 57, 32, 31, 28, 24, 12, 2 ]
# The curve was NOT fitting using this values, so I found a function in 
# scikit-learn that normalizes (multidim) arrays: [normalize][2]

# m = []
# m.append(original_ydata)
# ydata = normalize(m, norm='l2') * 10

# Why 10? This function is converting my original values in a range 
# going from [0.00014, ..., 0.002 ] or something similar. So "curve_fit" 
# couldn't find anything but a horizontal line crossing y = 1. 
# I tried multiplying by 5, 6, ..., 12, and I realized that 10 is 
# the maximum value that lets the maximum value of my array below 1.00, like 0.97599. 

# Length of both arrays is 209
# Y-axis data has been normalized BUT then multiplied by 10
ydata = array([  5.09124776e-04,   1.01824955e-03, ... , 9.75992196e-01])
xdata = array(range(0,len(ydata),1))

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

popt, pcov = curve_fit(sigmoid, xdata, ydata)

x = np.linspace(0, 250, 250)
y = sigmoid(x, *popt)

plt.plot(xdata, ydata, 'o', label='data')
plt.plot(x,y, linewidth=3.0, label='fit')
plt.ylim(0, 1.25)
plt.legend(loc='best')

# This (m, b, C) parameters not sure on where they are... popt, pcov? 
# y = C * sigmoid(m*x + b)

这个程序创建了你可以在下面看到的图。正如您所看到的,这是一个公平的调整,但我想如果我在 sigmoid 函数中更改 Y 的定义,通过添加一个 C 乘以第一个 1,我可能会得到更好的调整。还在继续。

似乎标准化数据(如 Ben Kuhn 在 cmets 中所建议的那样)是必需的步骤,否则不会创建曲线。但是,如果您的值被标准化为非常低的值(接近于零),则也不会绘制曲线。所以我将标准化向量乘以每 10,以将其缩放到更大的单位。然后程序简单地找到了曲线。我无法解释为什么,因为我是这方面的新手。请注意,这只是我的个人经验,我并不是说这是规则。

如果我打印 popt 和 pcov 我得到:

#> print popt
[  8.56332788e+01   6.53678132e-02]

#> print pcov
[[  1.65450283e-01   1.27146184e-07]
 [  1.27146184e-07   2.34426866e-06]]

而documentation on curve_fit 表示这些参数包含“参数的最佳值,以使平方误差之和最小化” 和前一个的协方差参数。

这 6 个值中的任何一个是表征 sigmoid 曲线的参数吗?因为如果是这样,那么问题就非常接近解决了! :-)

非常感谢!

【讨论】:

  • 参数在popt。您使用y = sigmoid(x, *popt) 构造曲线,它调用sigmoid 最后两个参数的值。
  • 那么第一个是斜率(x0),第二个是截距(k)?谢谢! :-)
猜你喜欢
  • 2018-01-20
  • 2020-07-07
  • 2011-05-17
  • 2018-11-20
  • 2015-04-06
  • 2021-11-18
  • 1970-01-01
  • 1970-01-01
  • 2017-11-12
相关资源
最近更新 更多