def l1_fit(index, y, beta_d2=1.0, beta_d1=1.0, beta_seasonal=1.0, beta_step=5.0, period=12, growth=0.0, step_permissives=None): assert isinstance(y, np.ndarray) assert isinstance(index, np.ndarray) #x must be integer type for seasonality to make sense assert index.dtype.kind == 'i' n = len(y) m = n-2 p = period ys, y_min, y_max = mu.scale_numpy(y) D1 = mu.get_first_derivative_matrix_nes(index) D2 = mu.get_second_derivative_matrix_nes(index) H = mu.get_step_function_matrix(n) T = mu.get_T_matrix(p) B = mu.get_B_matrix_nes(index, p) Q = B*T #define F_matrix from blocks like in paper zero = mu.zero_spmatrix ident = mu.identity_spmatrix gvec = spmatrix(growth, range(m), [0]*m) zero_m = spmatrix(0.0, range(m), [0]*m) zero_p = spmatrix(0.0, range(p), [0]*p) zero_n = spmatrix(0.0, range(n), [0]*n) step_reg = mu.get_step_function_reg(n, beta_step, permissives=step_permissives) F_matrix = sparse([ [ident(n), -beta_d1*D1, -beta_d2*D2, zero(p, n), zero(n)], [Q, zero(m, p-1), zero(m, p-1), -beta_seasonal*T, zero(n, p-1)], [H, zero(m, n), zero(m, n), zero(p, n), step_reg] ]) w_vector = sparse([ mu.np2spmatrix(ys), gvec, zero_m, zero_p, zero_n ]) solution_vector = np.asarray(l1.l1(matrix(F_matrix), matrix(w_vector))).squeeze() #separate xbase = solution_vector[0:n] s = solution_vector[n:n+p-1] h = solution_vector[n+p-1:] #scale back to original if y_max > y_min: scaling = y_max - y_min else: scaling = 1.0 xbase = xbase*scaling + y_min s = s*scaling h = h*scaling seas = np.asarray(Q*matrix(s)).squeeze() steps = np.asarray(H*matrix(h)).squeeze() x = xbase + seas + steps solution = {'xbase': xbase, 'seas': seas, 'steps': steps, 'x': x, 'h': h, 's': s} return solution
def l1_fit( index, y, beta_d2=1.0, beta_d1=1.0, beta_seasonal=1.0, beta_step=1000.0, growth=0.0, seasonality_matrix=None ): """ Least Absolute Deviation Time Series fitting function lower-level than version operating on actual dates :param index: ndarray, index of numeric x-values representing time :param y: ndarray, the time-series y-values :param beta_d2: L1 regularization parameter on the second derivative :param beta_d1: L1 regularization parameter on the first derivative :param beta_seasonal: L1 regularization parameter on the seasonal components :param beta_step: L1 regularization parameter on the step-function components :param growth: the default growth rate that is regularized toward default 0 :param seasonality_matrix: matrix which maps seasonality variables onto the index of data points allows the problem to be written in purely matrix form comes from get_seasonality_matrix function :return: """ # print "beta_d2: %s" % beta_d2 # print "beta_seasonal: %s" % beta_seasonal assert isinstance(y, np.ndarray) assert isinstance(index, np.ndarray) # x must be integer type for seasonality to make sense # assert index.dtype.kind == 'i' # dimensions n = len(y) m = n - 2 p = seasonality_matrix.size[1] ys, y_min, y_max = mu.scale_numpy(y) # set up matrices d1 = mu.get_first_derivative_matrix_nes(index) d2 = mu.get_second_derivative_matrix_nes(index) h = mu.get_step_function_matrix(n) t = mu.get_T_matrix(p) q = seasonality_matrix * t zero = mu.zero_spmatrix ident = mu.identity_spmatrix gvec = spmatrix(growth, range(m), [0] * m) zero_m = spmatrix(0.0, range(m), [0] * m) zero_p = spmatrix(0.0, range(p), [0] * p) zero_n = spmatrix(0.0, range(n), [0] * n) # allow step-function regularization to change at some points # is this really needed? step_reg = mu.get_step_function_reg(n, beta_step) # define F_matrix from blocks like in white paper # so that the problem can be stated as a standard LAD problem # and solvable with the l1 program F_matrix = sparse( [ [ident(n), -beta_d1 * d1, -beta_d2 * d2, zero(p, n), zero(n)], [q, zero(m, p - 1), zero(m, p - 1), -beta_seasonal * t, zero(n, p - 1)], [h, zero(m, n), zero(m, n), zero(p, n), step_reg], ] ) # convert to sparse matrix w_vector = sparse([mu.np2spmatrix(ys), gvec, zero_m, zero_p, zero_n]) # solve LAD problem and convert back to numpy array solution_vector = np.asarray(l1.l1(matrix(F_matrix), matrix(w_vector))).squeeze() # separate into components base = solution_vector[0:n] seasonal_parameters = solution_vector[n : n + p - 1] step_jumps = solution_vector[n + p - 1 :] # scale back to original if y_max > y_min: scaling = y_max - y_min else: scaling = 1.0 base = base * scaling + y_min seasonal_parameters *= scaling step_jumps *= scaling seasonal_component = np.asarray(q * matrix(seasonal_parameters)).squeeze() step_component = np.asarray(h * matrix(step_jumps)).squeeze() model_without_seasonal = base + step_component model = model_without_seasonal + seasonal_component solution = { "base": base, "seasonal_component": seasonal_component, "step_component": step_component, "model": model, "model_without_seasonal": model_without_seasonal, "step_jumps": step_jumps, "seasonal_parameters": seasonal_parameters, } return solution