概要 | |
---|---|
目的 | ユーザーごとの開始日, 終了日が記録されたレコードから開始日から終了日までのDate sequenceを作成する |
分類 | SQL Cookbook |
SQL | Standard SQL |
環境 | BigQuery |
Table of Contents
問題設定
(user_id, 開始日, 終了日)のレコードからなるデータが以下のように与えられたとします.
1
2
3
4
(1,'2020-09-01','2020-11-01'),
(2,'2020-09-01','2021-01-01'),
(3,'2020-10-01','2021-02-01'),
(4,'2020-11-01','2021-01-01')
このとき,以下のようにユーザーごとに開始日から終了日までの1ヶ月ごとのDate sequenceを作成したいとします.
user_id | observed_month |
---|---|
1 | 2020-09-01 |
1 | 2020-10-01 |
1 | 2020-11-01 |
2 | 2020-09-01 |
2 | 2020-10-01 |
2 | 2020-11-01 |
2 | 2020-12-01 |
2 | 2021-01-01 |
3 | 2020-10-01 |
3 | 2020-11-01 |
3 | 2020-12-01 |
3 | 2021-01-01 |
3 | 2021-02-01 |
4 | 2020-11-01 |
4 | 2020-12-01 |
4 | 2021-01-01 |
SQL実行例の紹介
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
WITH
raw_data AS(
SELECT
*
FROM UNNEST([STRUCT<user_id INT64, min_date DATE, max_date DATE>
(1,'2020-09-01','2020-11-01'),
(2,'2020-09-01','2021-01-01'),
(3,'2020-10-01','2021-02-01'),
(4,'2020-11-01','2021-01-01')
])
),
user_date_table AS(
SELECT
user_id,
GENERATE_DATE_ARRAY(min_date, max_date, INTERVAL 1 MONTH) AS date_range
FROM
raw_data
)
SELECT
user_id,
date_range_parsed AS observed_month
FROM
user_date_table,
UNNEST(date_range) AS date_range_parsed
UNNEST
のなかでarrayを作成し,explodeするという観点から以下のクエリも実行可能です(Special Thanks to SGSKさん)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
WITH
raw_data AS(
SELECT
*
FROM UNNEST([STRUCT<user_id INT64, min_date DATE, max_date DATE>
(1,'2020-09-01','2020-11-01'),
(2,'2020-09-01','2021-01-01'),
(3,'2020-10-01','2021-02-01'),
(4,'2020-11-01','2021-01-01')
])
)
SELECT
user_id,
date_range_parsed AS observed_month
FROM
raw_data,
UNNEST(GENERATE_DATE_ARRAY(min_date, max_date, INTERVAL 1 MONTH)) AS date_range_parsed
Python実行例の紹介
パターン1:
.apply(pd.Series).stack()
を活用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
## import
import pandas as pd
## Data作成
col_names = ['user_id', 'min_date', 'max_date']
record = [(1,'2020-09-01','2020-11-01'),
(2,'2020-09-01','2021-01-01'),
(3,'2020-10-01','2021-02-01'),
(4,'2020-11-01','2021-01-01')]
df = pd.DataFrame(record, columns=col_names)
## ユーザーごとのDate sequence作成
df['date_range'] = df.loc[:, ['min_date','max_date']].apply(
lambda x:pd.date_range(x.min_date, x.max_date , freq='MS'),
axis=1
)
res = df.set_index(['user_id'])['date_range'].apply(pd.Series).stack()
res = res.reset_index(level=0)
res.columns = ['user_id','observed_month']
res
パターン2:
pd.Dataframe().explode()
を活用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
## import
import pandas as pd
## Data作成
col_names = ['user_id', 'min_date', 'max_date']
record = [(1,'2020-09-01','2020-11-01'),
(2,'2020-09-01','2021-01-01'),
(3,'2020-10-01','2021-02-01'),
(4,'2020-11-01','2021-01-01')]
df = pd.DataFrame(record, columns=col_names)
## ユーザーごとのDate sequence作成
df['date_range'] = df.loc[:, ['min_date','max_date']].apply(
lambda x:pd.date_range(x.min_date, x.max_date , freq='MS'),
axis=1
)
df.explode('date_range').reset_index(drop=True)
Then,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
user_id min_date max_date date_range
0 1 2020-09-01 2020-11-01 2020-09-01
1 1 2020-09-01 2020-11-01 2020-10-01
2 1 2020-09-01 2020-11-01 2020-11-01
3 2 2020-09-01 2021-01-01 2020-09-01
4 2 2020-09-01 2021-01-01 2020-10-01
5 2 2020-09-01 2021-01-01 2020-11-01
6 2 2020-09-01 2021-01-01 2020-12-01
7 2 2020-09-01 2021-01-01 2021-01-01
8 3 2020-10-01 2021-02-01 2020-10-01
9 3 2020-10-01 2021-02-01 2020-11-01
10 3 2020-10-01 2021-02-01 2020-12-01
11 3 2020-10-01 2021-02-01 2021-01-01
12 3 2020-10-01 2021-02-01 2021-02-01
13 4 2020-11-01 2021-01-01 2020-11-01
14 4 2020-11-01 2021-01-01 2020-12-01
15 4 2020-11-01 2021-01-01 2021-01-01
References
オンラインマテリアル
統計
Python
math
Linux
Ubuntu 20.04 LTS
Shell
English
git
方法論
Ubuntu 22.04 LTS
統計検定
競技プログラミング
フーリエ解析
前処理
SQL
coding
コミュニケーション
Network
ssh
将棋
Data visualization
Docker
Econometrics
VSCode
statistical inference
GitHub Pages
apt
development
システム管理
Coffee
cloud
数値計算
素数
Book
Font
Metrics
Poetry
Ubuntu 24.04 LTS
architecture
aws
shell
systemctl
テンプレート
データ構造
ポワソン分布
会計分析
文字コード
環境構築
論文
App
Bayesian
Dynamic Programming
Keyboard
Processing
R
Steam
filesystem
quarto
regex
(注意:GitHub Accountが必要となります)