# # Regression with structural break # # Copyright (C) 2001, Wesley Phoa # # - uses LJ algorithm for integer minimization from regress import * from whrandom import randint def make_data(xs, ys): "Replace ys by percentages of average values." ys = array(ys) #return map(lambda x, z: (x, z), xs, ys / (sum(ys) / len(ys))) return map(lambda x, z: (x, z), xs, ys) def integer_min(f, lo, hi, shrink=0.8, guesses=10., gshrink=0.9): "Integer minimization via Monte Carlo." cache = {} width = hi - lo n = lo + width / 2 while width > 1: ns = [] fs = [] g = min(int(guesses), 1 + width / 2) while g: n = min(hi, randint(lo, lo + width)) ns.append(n) try: fs.append(cache[n]) except: cache[n] = f(n) fs.append(cache[n]) g = g - 1 n = ns[fs.index(min(fs))] width = min(int(width * shrink), width - 1) guesses = min(1 + guesses * gshrink, float(width)) lo = max(lo, n - width / 2) return n, f(n) def regress_with_break(model, data, n, init=None, objective=M_estimate, logdensity=Lorentzian): data0 = data[:n] data1 = data[n:] fit0, function0, formula0, R20 = regress(model, data0, init, objective) fit1, function1, formula1, R21 = regress(model, data1, init, objective) M_est = M_estimate(data0, function0, logdensity) \ + M_estimate(data1, function1, logdensity) return (function0, formula0), (function1, formula1), M_est def break_regress(model, data, min_n=5, init=None, objective=M_estimate, logdensity=Lorentzian): obj = lambda n, model=model, data=data, \ init=init, objective=objective, logdensity=logdensity: \ regress_with_break(model, data, n, init, objective, logdensity)[-1] n, err = integer_min(obj, min_n, len(data) - min_n) return n, regress_with_break(model, data, n, init, objective, logdensity) if __name__=='__main__': print integer_min(lambda x: sin(x / 100.), 0, 1000) print integer_min(lambda x: cos(x / 100.), 0, 1000) xs = array(range(50)) ys1 = list(5 + 3*xs) ys2 = list(4 + 2.5*xs) xs = 2 * list(xs) ys = array(ys1 + ys2) data = map(lambda x, z: (x, z), xs, ys) model = 'a0 + a1*x' print break_regress(model, data)