LoginSignup
6
3

More than 5 years have passed since last update.

BigQueryで移動平均を計算したい

Posted at

目的

ログデータの解析やら、株価の分析などで使える移動平均線を作りたいと思った。とりあえず、日が近いほど重みをつけたりなどをしない、単純移動平均としたい。
今回のケースの場合、1分ごとに1,000件以上のデータがあることを想定する。

データ例

単純なテーブルを作って、データを投入する

field type nullable
timestamp TIMESTAMP false
response_time INTEGER false

レスポンスのイメージ

[{
    "time": "2016-03-01 10:01:00Z",
    "response_time_1mins_avg": 60,
    "response_time_5mins_avg": 50,
    "response_time_10mins_avg": 40,
    "response_time_30mins_avg": 35,
    "response_time_1hours_avg": 30
},
{
    "time": "2016-03-01 10:00:00Z",
    "response_time_1mins_avg": 60,
    "response_time_5mins_avg": 50,
    "response_time_10mins_avg": 40,
    "response_time_30mins_avg": 35,
    "response_time_1hours_avg": 30
}]

クエリを組み立てる

SELECT
-- 1分ごとに情報を分割するため秒の情報を無視するフィールドを作る
SEC_TO_TIMESTAMP(INTEGER(TIMESTAMP_TO_SEC(timestamp) / 60) * 60) AS time,
-- 1分ごとの平均
AVG(response_time) AS response_time_1mins_avg,
-- 5分ごとの移動平均を1分ごとの平均から出す
AVG(response_time_1mins_avg) OVER (ORDER BY time RANGE BETWEEN (60 * 5 * 1000000) PRECEDING AND CURRENT ROW) AS response_time_5mins_avg,
-- 10分ごと
AVG(response_time_1mins_avg) OVER (ORDER BY time RANGE BETWEEN (60 * 10 * 1000000) PRECEDING AND CURRENT ROW) AS response_time_10mins_avg,
-- 30分ごと
AVG(response_time_1mins_avg) OVER (ORDER BY time RANGE BETWEEN (60 * 30 * 1000000) PRECEDING AND CURRENT ROW) AS response_time_30mins_avg,
-- 1時間ごと
AVG(response_time_1mins_avg) OVER (ORDER BY time RANGE BETWEEN (60 * 60 * 1000000) PRECEDING AND CURRENT ROW) AS response_time_60mins_avg
FROM
table
GROUP BY time
ORDER BY time DESC

OVER とは?

Window Function というモノ。
通常の集計関数だと、GROUP によって集計されるが、特定の行数内にあるもので集計したいというときは、この機能を使うと良いようだ。
上記のクエリでは、time (1分ごとのもの) の今の時間を基準に、time の昇順で現在の行から特定の範囲(1分、10分など) で平均値を集計している。

6
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
3