smurty
smurty

Reputation: 11

How to compute a moving average using jq?

Assume a Json array of numbers:

[ 1, 4, 6, 9, 8, 10, 5, 2]

I want to compute a 3 day moving average. The resulting array is computed by averaging the previous 3 entries.

So the first 3 entries don't care, the 4th is (1+4+6)/3, the 5th is (4+6+9)/3 and so on.

Conceptually, this is what I'm trying to do:

echo '[ 1, 4, 6, ... ]' | jq 'map(average(select(prev 3 array entries)))'

Upvotes: 1

Views: 2044

Answers (3)

jq170727
jq170727

Reputation: 14705

Here is a jq filter which uses a recursive function to compute the moving average of every n elements.

def avg(n):
    if length < n then empty   # base case
    else ( .[0:n] | add/n )    # average of first n elements
       , ( .[1:]  | avg(n) )   # recursive call
    end
;

avg(3)

Upvotes: 1

Jeff Mercado
Jeff Mercado

Reputation: 134521

You can use a filter like this:

def rolling_average(size): . as $items |
    [ range(0;length-size)
    | $items[.:.+size]
    | add/size
    ]
    ;
rolling_average(3)

The idea is to generate the range of indices to get the averages of, then take the average of those items.

Upvotes: 0

Nicpoń
Nicpoń

Reputation: 11

This question inspired me to learn jq, thanks!

my solution is

'. as $val | to_entries | map((.value + $val[.key-1] + $val[.key-2])/3)  | .[2:]'

First step, save whole array to variable $val

second step transforms array into array of object with keys (try it!, it transforms your example array into

[
  {
    "key": 0,
    "value": 1
  },
  {
    "key": 1,
    "value": 4
  },
  {
    "key": 2,
    "value": 6
  },
  {
    "key": 3,
    "value": 9
  },
  {
    "key": 4,
    "value": 8
  },
  {
    "key": 5,
    "value": 10
  },
  {
    "key": 6,
    "value": 5
  },
  {
    "key": 7,
    "value": 2
  }
]

)

third step gets value from each point and adds value of two previous steps

last step is optional, it throws out values "you don't care about"

Upvotes: 1

Related Questions