次のようなtimeseriesデータセットがあります。
uid | geom | date | count |
-------------------------------------
1 | FeatureA | 2016-02-01 | 1 |
2 | FeatureA | 2016-02-02 | 2 |
3 | FeatureA | 2016-02-03 | 3 |
4 | FeatureA | 2016-02-04 | 4 |
5 | FeatureA | 2016-02-05 | 5 |
6 | FeatureA | 2016-02-06 | 9 |
7 | FeatureA | 2016-02-07 | 11 |
8 | FeatureA | 2016-02-08 | 15 |
9 | FeatureA | 2016-02-09 | 17 |
10 | FeatureA | 2016-02-10 | 20 |
11 | FeatureB | 2016-02-01 | 2 |
12 | FeatureB | 2016-02-02 | 2 |
13 | FeatureB | 2016-02-03 | 8 |
14 | FeatureB | 2016-02-04 | 4 |
15 | FeatureB | 2016-02-05 | 5 |
16 | FeatureB | 2016-02-06 | 15 |
17 | FeatureB | 2016-02-07 | 11 |
18 | FeatureB | 2016-02-08 | 15 |
19 | FeatureB | 2016-02-09 | 19 |
20 | FeatureB | 2016-02-10 | 25 |
データセットの各フィーチャ(約2000フィーチャ)の7日間の移動平均を計算したいと思います。 Postgresのウィンドウで7日間の移動平均を計算するには、次のように使用できます here 。
次のコードはほとんど機能します:
SELECT geom,date,count,
AVG(count)
OVER(PARTITION BY geom ORDER BY geom, date ROWS BETWEEN CURRENT ROW AND 7 Following) AS rolling_avg_count
FROM features;
これにより、次の出力が得られます。
geom | date | count | rolling_avg_count
--------------------------------------------------
FeatureA | 2016-02-01 | 1 | 6.25
FeatureA | 2016-02-02 | 2 | 8.25
FeatureA | 2016-02-03 | 3 | 10.5
FeatureA | 2016-02-04 | 4 | 11.57
FeatureA | 2016-02-05 | 5 | 12.83
FeatureA | 2016-02-06 | 9 | 14.4
FeatureA | 2016-02-07 | 11 | 15.75
FeatureA | 2016-02-08 | 15 | 17.33
FeatureA | 2016-02-09 | 17 | 18.5
FeatureA | 2016-02-10 | 20 | 20
FeatureB | 2016-02-01 | 2 | 7.75
FeatureB | 2016-02-02 | 2 | 9.875
FeatureB | 2016-02-03 | 8 | 12.75
FeatureB | 2016-02-04 | 4 | 13.43
FeatureB | 2016-02-05 | 5 | 15
FeatureB | 2016-02-06 | 15 | 17
FeatureB | 2016-02-07 | 11 | 17.5
FeatureB | 2016-02-08 | 15 | 19.67
FeatureB | 2016-02-10 | 25 | 25
ただし、出力は、パーティションの最後まで平均の計算を続けます。たとえば、uid
10のローリング平均は20です(1つのレコードのみを使用して計算されます)。次の行が7行未満になったときに計算を停止します。
理想的には、出力は次のようになります。
geom | date | count | rolling_avg_count
--------------------------------------------------
FeatureA | 2016-02-01 | 1 | 6.25
FeatureA | 2016-02-02 | 2 | 8.25
FeatureA | 2016-02-03 | 3 | 10.5
FeatureA | 2016-02-04 | 4 | 11.57
FeatureA | 2016-02-05 | 5 |
FeatureA | 2016-02-06 | 9 |
FeatureA | 2016-02-07 | 11 |
FeatureA | 2016-02-08 | 15 |
FeatureA | 2016-02-09 | 17 |
FeatureA | 2016-02-10 | 20 |
FeatureB | 2016-02-01 | 2 | 7.75
FeatureB | 2016-02-02 | 2 | 9.875
FeatureB | 2016-02-03 | 8 | 12.75
FeatureB | 2016-02-04 | 4 | 13.43
FeatureB | 2016-02-05 | 5 |
FeatureB | 2016-02-06 | 15 |
FeatureB | 2016-02-07 | 11 |
FeatureB | 2016-02-08 | 15 |
FeatureB | 2016-02-10 | 25 |
これにより、望ましい結果が得られます-1つずれたエラーを調整した後②:
_SELECT geom, date, count
, CASE WHEN rn < 7 THEN NULL -- ②
ELSE round(rolling_avg_count, 2) END AS rolling_avg_count
FROM (
SELECT geom, date, count
, AVG(count) OVER (PARTITION BY geom
ORDER BY date -- ①
ROWS BETWEEN CURRENT ROW AND 6 FOLLOWING -- ②
) AS rolling_avg_count
, row_number() OVER (PARTITION BY geom ORDER BY date DESC) AS rn
FROM features
) sub;
_
db <> fiddle ここ
①_PARTITION BY geom
_では、_ORDER BY
_にgeom
は必要ありません。
②1つずれたエラーが発生しました:
7日間の移動平均を計算したい
しかし、8日移動平均(1 + 7)の計算を表示します。
次の行が7行より少ないときに計算を停止します。
ただし、6以降の行(表示された値11.57および13.43)。
私はそれを実際の7日間の平均にして、後続の行が6つ未満になると停止しました。
上記は、2番目のウィンドウ関数の降順の並べ替えのため、クエリプランに追加の並べ替えを追加します。
この代替クエリは、追加のcount()
でそれを回避します。
_SELECT geom, date, count
, CASE WHEN rn < 6 THEN NULL -- ③
ELSE round(rolling_avg_count, 2) END AS rolling_avg_count
FROM (
SELECT geom, date, count
, avg(count) OVER (PARTITION BY geom
ORDER BY date
ROWS BETWEEN CURRENT ROW AND 6 FOLLOWING
) AS rolling_avg_count
, count(*) OVER (PARTITION BY geom)
- row_number() OVER (PARTITION BY geom ORDER BY date) AS rn
FROM features
) sub;
_
db <> fiddle ここ
ウィンドウ関数を追加して、もう少し冗長にします。しかし、私はそれがより良いパフォーマンスを期待しています。
③0から始まる行番号に調整。 (_+ 1
_を追加するよりも安価です。)