Esempio n. 1
0
def regress_level_on_first_known(y: Y_TYPE,
                                 s: dict,
                                 k,
                                 a: A_TYPE = None,
                                 t: T_TYPE = None,
                                 e: E_TYPE = None) -> ([float], Any, Any):
    """ Very basic online regression skater, mostly for testing
           - Only one known in advance variable is utilized
           - Last value is ignored, unless a is None in which case we return 0.0
           - Empirical std is returned
    """
    y0 = wrap(y)[0]  # Ignore contemporaneous, exogenous variables
    if a:
        a0 = wrap(a)[0]  # Ignore all but the first known-in-advance variable

    if not s.get('k'):
        # First invocation
        s = {'p': {}}  # Prediction parade
        s['r'] = {}  # Regression state, not to be confused with hyper-param r
        s['k'] = k
        s['o'] = {
        }  # The "observance" will quarantine 'a' until it can be matched
    else:
        assert s['k'] == k  # Immutability

    if a is None:
        return [0] * k, [1.0] * k, s
    else:
        a_t, s['o'] = observance(y=[y0], o=s['o'], k=k,
                                 a=[a0])  # Update the observance
        if a_t is not None:  # This is the contemporaneous 'a', which was supplied k calls ago.
            if not s['r']:
                # When first calling the online regression algorithm we avoid the degenerate case
                # by sending it two observations.
                y_noise = 0.1 * (1e-6 + abs(y0)) * np.random.randn()
                x_noise = 0.1 * (1e-6 + abs(a0)) * np.random.randn()
                x = [a_t[0] - x_noise, a_t[0] + x_noise]
                y = [y0 - y_noise, y0 + y_noise]
                s['r'] = regress_one_helper(x=x, y=y, r=s['r'])
            else:
                s['r'] = regress_one_helper(x=a_t, y=[y0], r=s['r'])

            # Predict using contemporaneous alpha's
            x = [
                s['r']['alpha'] + s['r']['beta'] * ak[0] for ak in s['o']['a']
            ]

            # Push prediction into the parade and get the current bias/stderr
            bias, x_std, s['p'] = parade(p=s['p'], x=x, y=y0)
            return x, x_std, s  # TODO: Use the std implied by regression instead
        else:
            x = [y0] * k
            bias, x_std, s['p'] = parade(p=s['p'], x=x, y=y0)
            return x, x_std, s
Esempio n. 2
0
def moving_average_r1(y: Y_TYPE,
                      s,
                      k: int = 1,
                      a: A_TYPE = None,
                      t: T_TYPE = None,
                      e: E_TYPE = None,
                      r: R_TYPE = None):
    """ Exponential moving average, with empirical std

          r      weight to place on existing anchor point

    """
    assert r is not None
    y0 = wrap(y)[0]
    if not s.get('p'):
        s = {'p': {}, 'x': y0, 'rho': r}
        assert 0 <= s['rho'] <= 1, 'Expecting rho=r to be between 0 and 1'
    else:
        assert abs(r - s['rho']) < 1e-6, 'rho=r is immutable'

    if y0 is None:
        return None, s, None
    else:
        s['x'] = s['rho'] * s['x'] + (1 - s['rho']) * y0  # Make me better !
        x = [s['x'] * k]
        bias, x_std, s['p'] = parade(p=s['p'], x=x,
                                     y=y0)  # Update prediction queue
        return [s['x']] * k, x_std, s
Esempio n. 3
0
def empirical_last_value(y :Y_TYPE, s:dict, k:int =1, a:A_TYPE =None, t:T_TYPE =None, e:E_TYPE =None)->([float] , Any , Any):
    """ Last value cache, with empirical std """

    if not s.get('p'):
        s = {'p':{}}   # Initialize prediction parade

    if y is None:
        return None, None, s
    else:
        y0 = wrap(y)[0]       # Ignore the rest
        x = [y0]*k            # What a great prediction !
        bias, x_std, s['p'] = parade(p=s['p'], x=x, y=y0)  # update residual queue
        return x, x_std, s
Esempio n. 4
0
def fbprophet_skater_factory(y: Y_TYPE, s: dict, k: int, a: A_TYPE = None,
                             t: T_TYPE = None, e: E_TYPE = None,
                             emp_mass: float = 0.0, emp_std_mass: float = 0.0,
                             freq=None, recursive: bool = False,
                             model_params: dict = None,
                             n_max: int = None) -> ([float], Any, Any):
    """ Prophet skater with running prediction error moments
        Hyper-parameters are explicit here, whereas they are determined from r in actual skaters.
        Params of note:

             a: value of known-in-advance vars k step in advance (not contemporaneous with y)

    """

    assert 0 <= emp_mass <= 1
    assert 0 <= emp_std_mass <= 1

    if freq is None:
        freq = PROPHET_META['freq']
    if n_max is None:
        n_max = PROPHET_META['n_max']

    y = wrap(y)
    a = wrap(a)

    if not s.get('y'):
        s = {'p': {},     # parade
             'y': list(), # historical y
             'a': list(), # list of a known k steps in advance
             't': list(),
             'k': k}
    else:
        # Assert immutability of k, dimensions of y,a
        if s['y']:
            assert len(y) == len(s['y'][0])
            assert k == s['k']
        if s['a']:
            assert len(a) == len(s['a'][0])

    if y is None:
        return None, s, None
    else:
        s['y'].append(y)
        if a is not None:
            s['a'].append(a)
        if t is not None:
            assert isinstance(t,float), 'epoch time please'
            s['t'].append(t)

        if len(s['y']) > max(2 * k + 5, PROPHET_META['n_warm']):
            # Offset y, t, a are supplied to prophet interface
            t_arg = s['t'][k:] if t is not None else None
            a_arg = s['a']
            y_arg = s['y'][k:]
            x, x_std, forecast, model = prophet_iskater_factory(y=y_arg, k=k, a=a_arg, t=t_arg,
                                                                freq=freq, n_max=n_max,
                                                                recursive=recursive, model_params=model_params)
            s['m'] = True # Flag indicating a model has been fit (there is no point keeping the model itself, however)
        else:
            x = [y[0]] * k
            x_std = None

        # Get running mean prediction errors from the prediction parade
        x_resid, x_resid_std, s['p'] = parade(p=s['p'], x=x, y=y[0])
        x_resid = nonecast(x_resid,y[0])
        x_resid_std = nonecast(x_resid_std,1.0)

        # Compute center of mass between bias-corrected and uncorrected predictions
        x_corrected = np.array(x_resid) + np.array(x)
        x_center = nonecenter(m=[emp_mass, 1 - emp_mass], x=[x_corrected, x])
        x_std_center = nonecenter(m=[emp_std_mass, 1 - emp_std_mass], x=[x_resid_std, x_std])

        return x_center, x_std_center, s
Esempio n. 5
0
def residual_chaser_factory(y: Y_TYPE,
                            s: dict,
                            k: int = 1,
                            a: A_TYPE = None,
                            t: T_TYPE = None,
                            e: E_TYPE = None,
                            f1=None,
                            f2=None,
                            chase=1.0,
                            threshold=1.0,
                            r1=None,
                            r2=None) -> ([float], Any, Any):
    """ Last value cache, with empirical std and self-correction

          f1  - A skater making the primary prediction
          f2  - A skater designed to predict residuals
          chase     - Fraction of f2's residual prediction to use
          threshold - Number of standard deviations the residual prediction must exceed before we chase it.
          r1  - hyper-params for f1, if any
          r2  - hyper-params for f2, if any

    """
    y0 = wrap(y)[0]
    if not s.get('p1'):
        s = {'p1': {}, 'x': y0, 's1': {}, 's2': {}, 'n_obs': 0}

    if y0 is None:
        return None, None, s
    else:
        # Use the first skater to predict
        if r1 is None:
            x1, x1_std, s['s1'] = f1(y=y, s=s['s1'], k=k, a=a, t=t, e=e)
        else:
            x1, x1_std, s['s1'] = f1(y=y, s=s['s1'], k=k, a=a, t=t, e=e, r=r1)
        x1_error_mean, x1_error_std, s['p1'] = parade(
            p=s['p1'], x=x1, y=y0)  # Update prediction queue
        s['n_obs'] += 1

        # Use the second skater to predict mean residual k-steps ahead
        xke = x1_error_mean[-1]
        if r2 is None:
            xke_hat_mean, xke_hat_std, s['s2'] = f2(y=[xke],
                                                    s=s['s2'],
                                                    k=k,
                                                    a=a,
                                                    t=t,
                                                    e=e)
        else:
            xke_hat_mean, xke_hat_std, s['s2'] = f2(y=[xke],
                                                    s=s['s2'],
                                                    k=k,
                                                    a=a,
                                                    t=t,
                                                    e=e,
                                                    r=r2)

        # If the bias prediction is confident, adjust x1 chasing it towards the bias corrected value
        if s['n_obs'] > 10:
            for j in range(len(x1)):
                if abs(xke_hat_mean[j]) > threshold * xke_hat_std[j]:
                    x1[j] = x1[j] + chase * xke_hat_mean[j]

        return x1, x1_std, s