$
$ cat data.txt
H1,1.2
H1,2.3
H1,5.5
H1,6.6
H1,8.7
H1,4.1
H1,6.4
H1,7.8
H1,9.6
H1,3.2
H5,50.1
H5,54.2
H5,58.8
H5,60.9
H5,54.3
H5,52.7
H5,53.8
H5,60.1
H5,59.9
H5,59.4
H5,57.1
$
$ awk -F, '
BEGIN {window=5; half=1+int(window/2); iter=1; cnt=1; n=1; off=1; ptr=1}
{ if ($1 != prev) {
while (cnt > half) {
cnt--
split(line[off], delta, ",")
sum -= delta[2]
off++
avg = sum / cnt
printf("%s,%.1f\n", line[ptr], avg)
ptr++
}
delete line
sum = 0; iter = 1; cnt = 1;
off = 1; ptr = 1; n = 1
}
line[n] = $0
n++
sum += $2
if (iter >= half) {
if (iter == half) {
cnt = half
} else {
cnt++
if (cnt > window) {
cnt = window
split(line[off], delta, ",")
sum -= delta[2]
off++
}
}
avg = sum / cnt
printf("%s,%.1f\n", line[ptr], avg)
ptr++
}
prev = $1
iter++
}
END {
while (cnt > half) {
cnt--
split(line[off], delta, ",")
sum -= delta[2]
off++
avg = sum / cnt
printf("%s,%.1f\n", line[ptr], avg)
ptr++
}
}
' data.txt
H1,1.2,3.0
H1,2.3,3.9
H1,5.5,4.9
H1,6.6,5.4
H1,8.7,6.3
H1,4.1,6.7
H1,6.4,7.3
H1,7.8,6.2
H1,9.6,6.8
H1,3.2,6.9
H5,50.1,54.4
H5,54.2,56.0
H5,58.8,55.7
H5,60.9,56.2
H5,54.3,56.1
H5,52.7,56.4
H5,53.8,56.2
H5,60.1,57.2
H5,59.9,58.1
H5,59.4,59.1
H5,57.1,58.8
$
$
---------- Post updated at 03:34 AM ---------- Previous update was at 02:46 AM ----------
Calculating moving average appears to be pretty convoluted in imperative languages; however a declarative language like (modern) SQL provides syntactic sugar for solving this problem.
By any chance if you are extracting your data from a database, then you may want to check and leverage the power of SQL (specifically, "window" functions) to calculate moving average.
Here's an example with PostgreSQL 9.6, although window functions are available in Oracle, DB2, SQL Server, MySQL and MariaDB as well.
mydb=>
mydb=> SELECT VERSION();
version
---------------------------------------------------------------------------------------------------
PostgreSQL 9.6.3 on x86_64-pc-linux-gnu, compiled by gcc (Debian 6.3.0-18) 6.3.0 20170516, 64-bit
(1 row)
mydb=>
mydb=> SELECT * FROM data;
id | val
----+------
H1 | 1.2
H1 | 2.3
H1 | 5.5
H1 | 6.6
H1 | 8.7
H1 | 4.1
H1 | 6.4
H1 | 7.8
H1 | 9.6
H1 | 3.2
H5 | 50.1
H5 | 54.2
H5 | 58.8
H5 | 60.9
H5 | 54.3
H5 | 52.7
H5 | 53.8
H5 | 60.1
H5 | 59.9
H5 | 59.4
H5 | 57.1
(21 rows)
mydb=>
mydb=> SELECT id,
mydb-> val,
mydb-> ROUND(
mydb(> AVG(val) OVER (PARTITION BY id
mydb(> ROWS BETWEEN 2 PRECEDING AND 2 FOLLOWING
mydb(> )::NUMERIC,
mydb(> 1
mydb(> ) AS moving_avg
mydb-> FROM data
mydb-> ;
id | val | moving_avg
----+------+------------
H1 | 1.2 | 3.0
H1 | 2.3 | 3.9
H1 | 5.5 | 4.9
H1 | 6.6 | 5.4
H1 | 8.7 | 6.3
H1 | 4.1 | 6.7
H1 | 6.4 | 7.3
H1 | 7.8 | 6.2
H1 | 9.6 | 6.8
H1 | 3.2 | 6.9
H5 | 50.1 | 54.4
H5 | 54.2 | 56.0
H5 | 58.8 | 55.7
H5 | 60.9 | 56.2
H5 | 54.3 | 56.1
H5 | 52.7 | 56.4
H5 | 53.8 | 56.2
H5 | 60.1 | 57.2
H5 | 59.9 | 58.1
H5 | 59.4 | 59.1
H5 | 57.1 | 58.8
(21 rows)
mydb=>
mydb=>