PostgreSQL
 sql >> Base de données >  >> RDS >> PostgreSQL

Comment calculer une moyenne mobile exponentielle sur postgres ?

Vous pouvez définir votre propre fonction d'agrégation, puis l'utiliser avec une spécification de fenêtre pour obtenir la sortie agrégée à chaque étape plutôt qu'une valeur unique.

Ainsi, un agrégat est un élément d'état, et une fonction de transformation pour modifier cet état pour chaque ligne, et éventuellement une fonction de finalisation pour convertir l'état en une valeur de sortie. Pour un cas simple comme celui-ci, une simple fonction de transformation devrait suffire.

create function ema_func(numeric, numeric) returns numeric
  language plpgsql as $$
declare
  alpha numeric := 0.5;
begin
  -- uncomment the following line to see what the parameters mean
  -- raise info 'ema_func: % %', $1, $2;
  return case
              when $1 is null then $2
              else alpha * $2 + (1 - alpha) * $1
         end;
end
$$;
create aggregate ema(basetype = numeric, sfunc = ema_func, stype = numeric);

ce qui me donne :

[email protected]@[local] =# select x, ema(x, 0.1) over(w), ema(x, 0.2) over(w) from data window w as (order by n asc) limit 5;
     x     |      ema      |      ema      
-----------+---------------+---------------
 44.988564 |     44.988564 |     44.988564
   39.5634 |    44.4460476 |    43.9035312
 38.605724 |   43.86201524 |   42.84396976
 38.209646 |  43.296778316 |  41.917105008
 44.541264 | 43.4212268844 | 42.4419368064

Ces chiffres semblent correspondre à la feuille de calcul que vous avez ajoutée à la question.

En outre, vous pouvez définir la fonction pour passer alpha en tant que paramètre à partir de l'instruction :

create or replace function ema_func(state numeric, inval numeric, alpha numeric)
  returns numeric
  language plpgsql as $$
begin
  return case
         when state is null then inval
         else alpha * inval + (1-alpha) * state
         end;
end
$$;

create aggregate ema(numeric, numeric) (sfunc = ema_func, stype = numeric);

select x, ema(x, 0.5 /* alpha */) over (order by n asc) from data

De plus, cette fonction est en fait si simple qu'elle n'a pas du tout besoin d'être dans plpgsql, mais peut être juste une fonction sql, bien que vous ne puissiez pas faire référence aux paramètres par leur nom dans l'une d'entre elles :

create or replace function ema_func(state numeric, inval numeric, alpha numeric)
  returns numeric
  language sql as $$
select case
       when $1 is null then $2
       else $3 * $2 + (1-$3) * $1
       end
$$;