I have a number of short time-series ( maybe 30 - 100 time points ), and they have a general shape : they start high, come down quickly, may or may not plateau near zero, and then go back up. If they don't plateau, they look something like a simple quadratic, and if they do plateau, you may have a long series of zeros.
I'm trying to use the lmfit
module to fit a piecewise linear curve that is continuous. I'd like to infer where the line changes gradients, that is, I want to know where the curve "qualitatitively" changes gradients. I'd like to know when the gradient stops going down, and when it starts increasing again, in general terms. I'm having a few issues with it :
lmfit
seems to require at least two parameters, so I'm having to pass_
.- I'm unsure how to constrain one parameter to be greater than another.
- I'm getting
could not broadcast input array from shape (something) into shape (something)
errors
Here's some code. First, my objective function, to be minimised.
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
I then call,
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, _) )
The model is that, at some time t1, the gradient of the line changes, and the same happens at t2. Both of these parameters, as well as the gradients of the line segments ( and one intercept ), need to be inferred.
I could do this using MCMC methods, but I have too many of these series, and it would take too long.
Part of the traceback :
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)
A couple of examples of the time-series :
Any and all suggestions welcome. Thank you very much.