Python中的连续分段线性拟合

时间:2014-02-25 23:31:56

标签: python time-series mathematical-optimization minimization inference

我有一些很短的时间序列(可能是30到100个时间点),并且它们具有一般形状:它们从高位开始,快速下降,可能或者可能不是在零附近高原,然后再回升。如果他们不是高原,他们看起来像一个简单的二次方,如果他们做高原,你可能有一长串零。

我正在尝试使用lmfit模块来拟合连续的分段线性曲线。 我想推断线条在哪里改变渐变,也就是说,我想知道曲线“qualitatitively”改变渐变的位置。我想知道渐变何时停止下降,以及当它再次开始增加时,一般而言。我遇到了一些问题:

  • lmfit似乎至少需要两个参数,因此我必须通过_
  • 我不确定如何将一个参数限制为大于另一个参数。
  • 我收到could not broadcast input array from shape (something) into shape (something) 错误

这是一些代码。首先,我的目标函数,最小化。

def piecewiselinear(params, data, _) :

    t1 = params["t1"].value
    t2 = params["t2"].value
    m1 = params["m1"].value
    m2 = params["m2"].value
    m3 = params["m3"].value
    c = params["c"].value

    # Construct continuous, piecewise-linear fit
    model = np.zeros_like(data)
    model[:t1] = c + m1 * np.arange(t1)
    model[t1:t2] = model[t1-1] + m2 * np.arange(t2 - t1)
    model[t2:] = model[t2-1] + m3 * np.arange(len(data) - t2)

    return model - data

然后我打电话,

p = lmfit.Parameters()
p.add("t1", value = len(data)/4, min = 1, max = len(data))
p.add("t2", value = len(data)/4*3, min = 2, max = len(data))
p.add("m1", value = -100., max=0)
p.add("m2", value = 0.)
p.add("m3", value = 20., min = 1.)
p.add("c", min=0, value = 800.)

result = lmfit.minimize(piecewiselinear, p, args = (data, _) )

该模型是,在某个时间t1,线的梯度发生变化,同样的情况发生在t2。需要推断出这两个参数以及线段的梯度(和一个截距)。

我可以使用MCMC方法做到这一点,但我有太多这些系列,而且需要很长时间。

部分追溯:

     15     model = np.zeros_like(data)
     16     model[:t1] = c + m1 * np.arange(t1)
---> 17     model[t1:t2] = model[t1-1] + m2 * np.arange(t2-t1)
     18     model[t2:] = model[t2-1] + m3 * np.arange(len(data) - t2)
     19 

ValueError: could not broadcast input array from shape (151) into shape (28)

时间序列的几个例子: No plateau : steady drop and rise Long, sharp plateau

欢迎任何和所有建议。非常感谢你。

2 个答案:

答案 0 :(得分:0)

这是一个来自一个相当蛮力的3-pwlin钳工的情节; 将交换测试用例的粗略代码。 enter image description here

另外,有几个链接:
Fit-piecewise-linear-data 在dsp.stack上可能会给你一些想法;添加了一点 Dynamic programming
github.com/NickFoubert/simple-segment 有python用于分段,例如心电图有max_error(不是件数), 来自Keogh等人的一篇好文章, An online algorithm for segmenting time series,2001,8p。

还有一种可能的替代方案:你能否在py ~ x^p中使用log y ~ p log x^2。 (将x转换为[-1 .. 1]和y> 1e-6左右后)? 这将是健壮快速,并且易于策划和理解 人们应该重视目的 这样错误大致平淡而正常 另外一个人可以将左右两半分开p p'

答案 1 :(得分:0)

走下蛮力路线似乎可以解决问题。我只是测试开关点的所有组合并选择最合适的。它非常快速且可以相当稳健。这是一个特别适合的结果。

enter image description here

我强迫第二行的渐变为零。这样可以确保我们无法适合两条线并且非常适合一条线,这可能会获得更高的分数(我在这里使用R ^ 2值的总和)。绿色标记切换点,这些应该适用于我的应用程序。

我想学习更优雅的想要做到这一点,但与此同时,这是一个选择...