Malloy can compute moving averages on resultsets.
The queries below use the following model
source: order_items is duckdb.table('../data/order_items.parquet') extend { measure: user_count is count(distinct user_id) order_count is count() }
Simple Moving Average
run: order_items -> { group_by: order_month is created_at.month aggregate: order_count calculate: moving_avg_order_count is avg_moving(order_count, 3) order_by: order_month }
order_month | order_count | moving_avg_order_count |
---|---|---|
2019-01 | 1,262 | 1,262 |
2019-02 | 1,230 | 1,246 |
2019-03 | 1,507 | 1,333 |
2019-04 | 1,826 | 1,456.25 |
2019-05 | 2,044 | 1,651.75 |
2019-06 | 2,150 | 1,881.75 |
2019-07 | 2,382 | 2,100.5 |
2019-08 | 2,632 | 2,302 |
2019-09 | 2,902 | 2,516.5 |
2019-10 | 3,214 | 2,782.5 |
2019-11 | 3,387 | 3,033.75 |
2019-12 | 4,038 | 3,385.25 |
2020-01 | 3,743 | 3,595.5 |
2020-02 | 3,570 | 3,684.5 |
2020-03 | 4,263 | 3,903.5 |
2020-04 | 4,183 | 3,939.75 |
2020-05 | 4,019 | 4,008.75 |
2020-06 | 4,292 | 4,189.25 |
2020-07 | 4,549 | 4,260.75 |
2020-08 | 4,874 | 4,433.5 |
2020-09 | 5,032 | 4,686.75 |
2020-10 | 5,422 | 4,969.25 |
2020-11 | 5,782 | 5,277.5 |
2020-12 | 6,293 | 5,632.25 |
2021-01 | 5,897 | 5,848.5 |
2021-02 | 5,821 | 5,948.25 |
2021-03 | 6,547 | 6,139.5 |
2021-04 | 6,380 | 6,161.25 |
2021-05 | 6,378 | 6,281.5 |
2021-06 | 6,305 | 6,402.5 |
2021-07 | 6,813 | 6,469 |
2021-08 | 7,142 | 6,659.5 |
2021-09 | 7,886 | 7,036.5 |
2021-10 | 7,814 | 7,413.75 |
2021-11 | 8,063 | 7,726.25 |
2021-12 | 9,103 | 8,216.5 |
2022-01 | 8,609 | 8,397.25 |
2022-02 | 8,174 | 8,487.25 |
2022-03 | 9,441 | 8,831.75 |
2022-04 | 9,100 | 8,831 |
2022-05 | 9,730 | 9,111.25 |
2022-06 | 9,297 | 9,392 |
2022-07 | 9,668 | 9,448.75 |
2022-08 | 10,481 | 9,794 |
2022-09 | 11,213 | 10,164.75 |
2022-10 | 11,398 | 10,690 |
2022-11 | 5,163 | 9,563.75 |
[ { "order_month": "2019-01-01T00:00:00.000Z", "order_count": 1262, "moving_avg_order_count": 1262 }, { "order_month": "2019-02-01T00:00:00.000Z", "order_count": 1230, "moving_avg_order_count": 1246 }, { "order_month": "2019-03-01T00:00:00.000Z", "order_count": 1507, "moving_avg_order_count": 1333 }, { "order_month": "2019-04-01T00:00:00.000Z", "order_count": 1826, "moving_avg_order_count": 1456.25 }, { "order_month": "2019-05-01T00:00:00.000Z", "order_count": 2044, "moving_avg_order_count": 1651.75 }, { "order_month": "2019-06-01T00:00:00.000Z", "order_count": 2150, "moving_avg_order_count": 1881.75 }, { "order_month": "2019-07-01T00:00:00.000Z", "order_count": 2382, "moving_avg_order_count": 2100.5 }, { "order_month": "2019-08-01T00:00:00.000Z", "order_count": 2632, "moving_avg_order_count": 2302 }, { "order_month": "2019-09-01T00:00:00.000Z", "order_count": 2902, "moving_avg_order_count": 2516.5 }, { "order_month": "2019-10-01T00:00:00.000Z", "order_count": 3214, "moving_avg_order_count": 2782.5 }, { "order_month": "2019-11-01T00:00:00.000Z", "order_count": 3387, "moving_avg_order_count": 3033.75 }, { "order_month": "2019-12-01T00:00:00.000Z", "order_count": 4038, "moving_avg_order_count": 3385.25 }, { "order_month": "2020-01-01T00:00:00.000Z", "order_count": 3743, "moving_avg_order_count": 3595.5 }, { "order_month": "2020-02-01T00:00:00.000Z", "order_count": 3570, "moving_avg_order_count": 3684.5 }, { "order_month": "2020-03-01T00:00:00.000Z", "order_count": 4263, "moving_avg_order_count": 3903.5 }, { "order_month": "2020-04-01T00:00:00.000Z", "order_count": 4183, "moving_avg_order_count": 3939.75 }, { "order_month": "2020-05-01T00:00:00.000Z", "order_count": 4019, "moving_avg_order_count": 4008.75 }, { "order_month": "2020-06-01T00:00:00.000Z", "order_count": 4292, "moving_avg_order_count": 4189.25 }, { "order_month": "2020-07-01T00:00:00.000Z", "order_count": 4549, "moving_avg_order_count": 4260.75 }, { "order_month": "2020-08-01T00:00:00.000Z", "order_count": 4874, "moving_avg_order_count": 4433.5 }, { "order_month": "2020-09-01T00:00:00.000Z", "order_count": 5032, "moving_avg_order_count": 4686.75 }, { "order_month": "2020-10-01T00:00:00.000Z", "order_count": 5422, "moving_avg_order_count": 4969.25 }, { "order_month": "2020-11-01T00:00:00.000Z", "order_count": 5782, "moving_avg_order_count": 5277.5 }, { "order_month": "2020-12-01T00:00:00.000Z", "order_count": 6293, "moving_avg_order_count": 5632.25 }, { "order_month": "2021-01-01T00:00:00.000Z", "order_count": 5897, "moving_avg_order_count": 5848.5 }, { "order_month": "2021-02-01T00:00:00.000Z", "order_count": 5821, "moving_avg_order_count": 5948.25 }, { "order_month": "2021-03-01T00:00:00.000Z", "order_count": 6547, "moving_avg_order_count": 6139.5 }, { "order_month": "2021-04-01T00:00:00.000Z", "order_count": 6380, "moving_avg_order_count": 6161.25 }, { "order_month": "2021-05-01T00:00:00.000Z", "order_count": 6378, "moving_avg_order_count": 6281.5 }, { "order_month": "2021-06-01T00:00:00.000Z", "order_count": 6305, "moving_avg_order_count": 6402.5 }, { "order_month": "2021-07-01T00:00:00.000Z", "order_count": 6813, "moving_avg_order_count": 6469 }, { "order_month": "2021-08-01T00:00:00.000Z", "order_count": 7142, "moving_avg_order_count": 6659.5 }, { "order_month": "2021-09-01T00:00:00.000Z", "order_count": 7886, "moving_avg_order_count": 7036.5 }, { "order_month": "2021-10-01T00:00:00.000Z", "order_count": 7814, "moving_avg_order_count": 7413.75 }, { "order_month": "2021-11-01T00:00:00.000Z", "order_count": 8063, "moving_avg_order_count": 7726.25 }, { "order_month": "2021-12-01T00:00:00.000Z", "order_count": 9103, "moving_avg_order_count": 8216.5 }, { "order_month": "2022-01-01T00:00:00.000Z", "order_count": 8609, "moving_avg_order_count": 8397.25 }, { "order_month": "2022-02-01T00:00:00.000Z", "order_count": 8174, "moving_avg_order_count": 8487.25 }, { "order_month": "2022-03-01T00:00:00.000Z", "order_count": 9441, "moving_avg_order_count": 8831.75 }, { "order_month": "2022-04-01T00:00:00.000Z", "order_count": 9100, "moving_avg_order_count": 8831 }, { "order_month": "2022-05-01T00:00:00.000Z", "order_count": 9730, "moving_avg_order_count": 9111.25 }, { "order_month": "2022-06-01T00:00:00.000Z", "order_count": 9297, "moving_avg_order_count": 9392 }, { "order_month": "2022-07-01T00:00:00.000Z", "order_count": 9668, "moving_avg_order_count": 9448.75 }, { "order_month": "2022-08-01T00:00:00.000Z", "order_count": 10481, "moving_avg_order_count": 9794 }, { "order_month": "2022-09-01T00:00:00.000Z", "order_count": 11213, "moving_avg_order_count": 10164.75 }, { "order_month": "2022-10-01T00:00:00.000Z", "order_count": 11398, "moving_avg_order_count": 10690 }, { "order_month": "2022-11-01T00:00:00.000Z", "order_count": 5163, "moving_avg_order_count": 9563.75 } ]
SELECT DATE_TRUNC('month', order_items."created_at") as "order_month", COUNT( 1) as "order_count", AVG((COUNT( 1))) OVER( ORDER BY DATE_TRUNC('month', order_items."created_at") ASC NULLS LAST ROWS BETWEEN 3 PRECEDING AND 0 FOLLOWING) as "moving_avg_order_count" FROM '../data/order_items.parquet' as order_items GROUP BY 1 ORDER BY 1 ASC NULLS LAST
Visualizing the Results
run: order_items -> { # line_chart nest: non_averaged is { group_by: order_month is created_at.month aggregate: order_count order_by: order_month } # line_chart nest: moving_averaged is { group_by: order_month is created_at.month calculate: moving_avg_order_count is avg_moving(order_count, 3) order_by: order_month } }
non_averaged | moving_averaged |
---|---|
[ { "non_averaged": [ { "order_month": "2019-01-01T00:00:00.000Z", "order_count": 1262 }, { "order_month": "2019-02-01T00:00:00.000Z", "order_count": 1230 }, { "order_month": "2019-03-01T00:00:00.000Z", "order_count": 1507 }, { "order_month": "2019-04-01T00:00:00.000Z", "order_count": 1826 }, { "order_month": "2019-05-01T00:00:00.000Z", "order_count": 2044 }, { "order_month": "2019-06-01T00:00:00.000Z", "order_count": 2150 }, { "order_month": "2019-07-01T00:00:00.000Z", "order_count": 2382 }, { "order_month": "2019-08-01T00:00:00.000Z", "order_count": 2632 }, { "order_month": "2019-09-01T00:00:00.000Z", "order_count": 2902 }, { "order_month": "2019-10-01T00:00:00.000Z", "order_count": 3214 }, { "order_month": "2019-11-01T00:00:00.000Z", "order_count": 3387 }, { "order_month": "2019-12-01T00:00:00.000Z", "order_count": 4038 }, { "order_month": "2020-01-01T00:00:00.000Z", "order_count": 3743 }, { "order_month": "2020-02-01T00:00:00.000Z", "order_count": 3570 }, { "order_month": "2020-03-01T00:00:00.000Z", "order_count": 4263 }, { "order_month": "2020-04-01T00:00:00.000Z", "order_count": 4183 }, { "order_month": "2020-05-01T00:00:00.000Z", "order_count": 4019 }, { "order_month": "2020-06-01T00:00:00.000Z", "order_count": 4292 }, { "order_month": "2020-07-01T00:00:00.000Z", "order_count": 4549 }, { "order_month": "2020-08-01T00:00:00.000Z", "order_count": 4874 }, { "order_month": "2020-09-01T00:00:00.000Z", "order_count": 5032 }, { "order_month": "2020-10-01T00:00:00.000Z", "order_count": 5422 }, { "order_month": "2020-11-01T00:00:00.000Z", "order_count": 5782 }, { "order_month": "2020-12-01T00:00:00.000Z", "order_count": 6293 }, { "order_month": "2021-01-01T00:00:00.000Z", "order_count": 5897 }, { "order_month": "2021-02-01T00:00:00.000Z", "order_count": 5821 }, { "order_month": "2021-03-01T00:00:00.000Z", "order_count": 6547 }, { "order_month": "2021-04-01T00:00:00.000Z", "order_count": 6380 }, { "order_month": "2021-05-01T00:00:00.000Z", "order_count": 6378 }, { "order_month": "2021-06-01T00:00:00.000Z", "order_count": 6305 }, { "order_month": "2021-07-01T00:00:00.000Z", "order_count": 6813 }, { "order_month": "2021-08-01T00:00:00.000Z", "order_count": 7142 }, { "order_month": "2021-09-01T00:00:00.000Z", "order_count": 7886 }, { "order_month": "2021-10-01T00:00:00.000Z", "order_count": 7814 }, { "order_month": "2021-11-01T00:00:00.000Z", "order_count": 8063 }, { "order_month": "2021-12-01T00:00:00.000Z", "order_count": 9103 }, { "order_month": "2022-01-01T00:00:00.000Z", "order_count": 8609 }, { "order_month": "2022-02-01T00:00:00.000Z", "order_count": 8174 }, { "order_month": "2022-03-01T00:00:00.000Z", "order_count": 9441 }, { "order_month": "2022-04-01T00:00:00.000Z", "order_count": 9100 }, { "order_month": "2022-05-01T00:00:00.000Z", "order_count": 9730 }, { "order_month": "2022-06-01T00:00:00.000Z", "order_count": 9297 }, { "order_month": "2022-07-01T00:00:00.000Z", "order_count": 9668 }, { "order_month": "2022-08-01T00:00:00.000Z", "order_count": 10481 }, { "order_month": "2022-09-01T00:00:00.000Z", "order_count": 11213 }, { "order_month": "2022-10-01T00:00:00.000Z", "order_count": 11398 }, { "order_month": "2022-11-01T00:00:00.000Z", "order_count": 5163 } ], "moving_averaged": [ { "order_month": "2019-01-01T00:00:00.000Z", "moving_avg_order_count": 1262 }, { "order_month": "2019-02-01T00:00:00.000Z", "moving_avg_order_count": 1246 }, { "order_month": "2019-03-01T00:00:00.000Z", "moving_avg_order_count": 1333 }, { "order_month": "2019-04-01T00:00:00.000Z", "moving_avg_order_count": 1456.25 }, { "order_month": "2019-05-01T00:00:00.000Z", "moving_avg_order_count": 1651.75 }, { "order_month": "2019-06-01T00:00:00.000Z", "moving_avg_order_count": 1881.75 }, { "order_month": "2019-07-01T00:00:00.000Z", "moving_avg_order_count": 2100.5 }, { "order_month": "2019-08-01T00:00:00.000Z", "moving_avg_order_count": 2302 }, { "order_month": "2019-09-01T00:00:00.000Z", "moving_avg_order_count": 2516.5 }, { "order_month": "2019-10-01T00:00:00.000Z", "moving_avg_order_count": 2782.5 }, { "order_month": "2019-11-01T00:00:00.000Z", "moving_avg_order_count": 3033.75 }, { "order_month": "2019-12-01T00:00:00.000Z", "moving_avg_order_count": 3385.25 }, { "order_month": "2020-01-01T00:00:00.000Z", "moving_avg_order_count": 3595.5 }, { "order_month": "2020-02-01T00:00:00.000Z", "moving_avg_order_count": 3684.5 }, { "order_month": "2020-03-01T00:00:00.000Z", "moving_avg_order_count": 3903.5 }, { "order_month": "2020-04-01T00:00:00.000Z", "moving_avg_order_count": 3939.75 }, { "order_month": "2020-05-01T00:00:00.000Z", "moving_avg_order_count": 4008.75 }, { "order_month": "2020-06-01T00:00:00.000Z", "moving_avg_order_count": 4189.25 }, { "order_month": "2020-07-01T00:00:00.000Z", "moving_avg_order_count": 4260.75 }, { "order_month": "2020-08-01T00:00:00.000Z", "moving_avg_order_count": 4433.5 }, { "order_month": "2020-09-01T00:00:00.000Z", "moving_avg_order_count": 4686.75 }, { "order_month": "2020-10-01T00:00:00.000Z", "moving_avg_order_count": 4969.25 }, { "order_month": "2020-11-01T00:00:00.000Z", "moving_avg_order_count": 5277.5 }, { "order_month": "2020-12-01T00:00:00.000Z", "moving_avg_order_count": 5632.25 }, { "order_month": "2021-01-01T00:00:00.000Z", "moving_avg_order_count": 5848.5 }, { "order_month": "2021-02-01T00:00:00.000Z", "moving_avg_order_count": 5948.25 }, { "order_month": "2021-03-01T00:00:00.000Z", "moving_avg_order_count": 6139.5 }, { "order_month": "2021-04-01T00:00:00.000Z", "moving_avg_order_count": 6161.25 }, { "order_month": "2021-05-01T00:00:00.000Z", "moving_avg_order_count": 6281.5 }, { "order_month": "2021-06-01T00:00:00.000Z", "moving_avg_order_count": 6402.5 }, { "order_month": "2021-07-01T00:00:00.000Z", "moving_avg_order_count": 6469 }, { "order_month": "2021-08-01T00:00:00.000Z", "moving_avg_order_count": 6659.5 }, { "order_month": "2021-09-01T00:00:00.000Z", "moving_avg_order_count": 7036.5 }, { "order_month": "2021-10-01T00:00:00.000Z", "moving_avg_order_count": 7413.75 }, { "order_month": "2021-11-01T00:00:00.000Z", "moving_avg_order_count": 7726.25 }, { "order_month": "2021-12-01T00:00:00.000Z", "moving_avg_order_count": 8216.5 }, { "order_month": "2022-01-01T00:00:00.000Z", "moving_avg_order_count": 8397.25 }, { "order_month": "2022-02-01T00:00:00.000Z", "moving_avg_order_count": 8487.25 }, { "order_month": "2022-03-01T00:00:00.000Z", "moving_avg_order_count": 8831.75 }, { "order_month": "2022-04-01T00:00:00.000Z", "moving_avg_order_count": 8831 }, { "order_month": "2022-05-01T00:00:00.000Z", "moving_avg_order_count": 9111.25 }, { "order_month": "2022-06-01T00:00:00.000Z", "moving_avg_order_count": 9392 }, { "order_month": "2022-07-01T00:00:00.000Z", "moving_avg_order_count": 9448.75 }, { "order_month": "2022-08-01T00:00:00.000Z", "moving_avg_order_count": 9794 }, { "order_month": "2022-09-01T00:00:00.000Z", "moving_avg_order_count": 10164.75 }, { "order_month": "2022-10-01T00:00:00.000Z", "moving_avg_order_count": 10690 }, { "order_month": "2022-11-01T00:00:00.000Z", "moving_avg_order_count": 9563.75 } ] } ]
WITH __stage0 AS ( SELECT group_set, CASE WHEN group_set=1 THEN DATE_TRUNC('month', order_items."created_at") END as "order_month__1", CASE WHEN group_set=1 THEN COUNT( 1) END as "order_count__1", CASE WHEN group_set=2 THEN DATE_TRUNC('month', order_items."created_at") END as "order_month__2", AVG((CASE WHEN group_set=2 THEN COUNT( 1) END)) OVER(PARTITION BY group_set ORDER BY CASE WHEN group_set=2 THEN DATE_TRUNC('month', order_items."created_at") END ASC NULLS LAST ROWS BETWEEN 3 PRECEDING AND 0 FOLLOWING) as "moving_avg_order_count__2" FROM '../data/order_items.parquet' as order_items CROSS JOIN (SELECT UNNEST(GENERATE_SERIES(0,2,1)) as group_set ) as group_set GROUP BY 1,2,4 ) SELECT COALESCE(LIST({ "order_month": "order_month__1", "order_count": "order_count__1"} ORDER BY "order_month__1" ASC NULLS LAST) FILTER (WHERE group_set=1),[]) as "non_averaged", COALESCE(LIST({ "order_month": "order_month__2", "moving_avg_order_count": "moving_avg_order_count__2"} ORDER BY "order_month__2" ASC NULLS LAST) FILTER (WHERE group_set=2),[]) as "moving_averaged" FROM __stage0
Displaying Charts in Nested Queries
In this example, we've added two queries to the flights
source, one showing flights by month without the moving average applied, and one with the moving average applied. We then use these queries to show charts of flight count for each airport over time.
source: flights is duckdb.table('../data/flights.parquet') extend { measure: flight_count is count() dimension: dep_month is dep_time.month # line_chart view: non_averaged is { group_by: dep_month aggregate: flight_count order_by: dep_month } # line_chart view: moving_averaged is { group_by: dep_month calculate: moving_avg_flight_count is avg_moving(flight_count, 3) order_by: dep_month } }
run: flights -> { group_by: destination aggregate: flight_count nest: non_averaged nest: moving_averaged }
destination | flight_count | non_averaged | moving_averaged |
---|---|---|---|
ATL | 17,832 | ||
DFW | 17,776 | ||
ORD | 14,213 | ||
PHX | 12,477 | ||
LAS | 11,092 | ||
LAX | 11,074 | ||
MSP | 9,769 | ||
DTW | 8,141 | ||
PHL | 7,694 | ||
LGA | 7,625 | ||
BWI | 7,190 | ||
DEN | 7,187 | ||
CLT | 7,113 | ||
SEA | 7,000 | ||
MCO | 6,796 | ||
DCA | 6,695 | ||
IAH | 6,623 | ||
MDW | 6,614 | ||
BOS | 5,799 | ||
EWR | 5,137 | ||
CLE | 5,125 | ||
OAK | 5,082 | ||
SAN | 5,080 | ||
TPA | 4,881 | ||
PIT | 4,507 | ||
SFO | 4,502 | ||
BNA | 4,279 | ||
STL | 4,098 | ||
MCI | 4,081 | ||
IAD | 3,932 | ||
SJC | 3,818 | ||
JFK | 3,698 | ||
FLL | 3,608 | ||
PDX | 3,602 | ||
SMF | 3,580 | ||
HOU | 3,428 | ||
CVG | 3,292 | ||
MSY | 3,265 | ||
ABQ | 2,762 | ||
SLC | 2,745 | ||
ONT | 2,645 | ||
RDU | 2,457 | ||
MIA | 2,369 | ||
PVD | 2,364 | ||
MEM | 2,250 | ||
IND | 2,229 | ||
BDL | 2,162 |