【解説】時系列ずらしの方法を学ぶ | データサイエンス100本ノック【問41〜問42 回答】

【解説】時系列ずらしの方法を学ぶ | データサイエンス100本ノック【問41〜問42 回答】





目次

この記事の対象者



・ データサイエンティストを目指している人

・ Pythonで時系列ずらしの方法を学びたい人



以降はデータサイエンス100本ノックの問題を題材に、時系列ずらしの方法について学んでいきます。


データサイエンス100本ノックの始め方は、以下の記事を参考にしていただければと思います。


>>データサイエンス100本ノックの始め方を確認する


第41問目: データフレームの行ずらし

P-041: レシート明細データフレーム(df_receipt)の売上金額(amount)を日付(sales_ymd)ごとに集計し、前日からの売上金額増減を計算せよ。なお、計算結果は10件表示すればよい。



まずは、df_receiptsales_ymd列とamount列のみ抽出し、sales_ymdでグルーピングすれば良いね。「前日からの売上金額増減の計算」はどうやればいいだろう?


「前日からの売上金額増減の計算」は、与えられたデータフレームの行を1行ずらして差分をとることで、前日からの売上金額の増減を計算することができます。


まずは、df_receiptsales_ymd列とamount列のみ抽出し、sales_ymdでグルーピングします。


その後に、amountに対して合計値を計算し、indexを再割り当てましょう。


df_receiptのsales_ymd列とamount列のみ抽出し、sales_ymdでグルーピング
1
2
df_sales_amount_by_date = df_receipt[['sales_ymd', 'amount']].groupby('sales_ymd').sum().reset_index()
df_sales_amount_by_date


出力
1
2
3
4
5
6
7
8
9
10
11
12
13
	sales_ymd	amount
0 20170101 33723
1 20170102 24165
2 20170103 27503
3 20170104 36165
4 20170105 37830
... ... ...
1029 20191027 37484
1030 20191028 40161
1031 20191029 36091
1032 20191030 26602
1033 20191031 25216
1034 rows × 2 columns



繰り返しになりますが、この問題に対する方針を整理します。


この問題においては、df_sales_amount_by_dateというデータフレームを1行下にずらしたデータフレームを作成し、両者のデータフレームのamountの差分を取ることで、前日からの売上金額の増減を計算していきたいと思います。


ここで作ったdf_sales_amount_by_dateと、当該データフレームを1行下にシフトしたデータフレームを結合します。


データフレームの行または列をずらすにはshift()を使用します。

>>pandas.DataFrame.shift


shift()は、引数に数値を指定することでずらし幅を指定することが出来ます。


引数に数値を指定しなかった場合は、下方向に1行ずれます。行数はそのままなので、最後の行のデータは削除されます。


``df_sales_amount_by_date``と、当該データフレームを1行下にシフトしたデータフレームを結合
1
2
df_sales_amount_by_date = pd.concat([df_sales_amount_by_date, df_sales_amount_by_date.shift()], axis=1)
df_sales_amount_by_date


出力
1
2
3
4
5
6
7
8
9
10
11
12
13
	sales_ymd	amount	sales_ymd	amount
0 20170101 33723 NaN NaN
1 20170102 24165 20170101.0 33723.0
2 20170103 27503 20170102.0 24165.0
3 20170104 36165 20170103.0 27503.0
4 20170105 37830 20170104.0 36165.0
... ... ... ... ...
1029 20191027 37484 20191026.0 51771.0
1030 20191028 40161 20191027.0 37484.0
1031 20191029 36091 20191028.0 40161.0
1032 20191030 26602 20191029.0 36091.0
1033 20191031 25216 20191030.0 26602.0
1034 rows × 4 columns


出力されたデータフレームのカラム名を見てみると、sales_ymdというカラム名とamountというカラム名が2つずつあり区別できません。


なので、カラム名を1列目から順番にsales_ymd, amount, lag_ymd, lag_amountに変更しています。


カラム名を変更
1
2
df_sales_amount_by_date.columns = ['sales_ymd', 'amount', 'lag_ymd', 'lag_amount']
df_sales_amount_by_date


出力
1
2
3
4
5
6
7
8
9
10
11
12
13
14

sales_ymd amount lag_ymd lag_amount
0 20170101 33723 NaN NaN
1 20170102 24165 20170101.0 33723.0
2 20170103 27503 20170102.0 24165.0
3 20170104 36165 20170103.0 27503.0
4 20170105 37830 20170104.0 36165.0
... ... ... ... ...
1029 20191027 37484 20191026.0 51771.0
1030 20191028 40161 20191027.0 37484.0
1031 20191029 36091 20191028.0 40161.0
1032 20191030 26602 20191029.0 36091.0
1033 20191031 25216 20191030.0 26602.0
1034 rows × 4 columns


df_sales_amount_by_dateに新しいカラムdiff_amountを作成し、amount列とlag_amount列の差を取ったデータを追加します。


新しいカラムdiff_amountを作成し、amount列とlag_amount列の差を取ったデータを追加
1
2
df_sales_amount_by_date['diff_amount'] = df_sales_amount_by_date['amount'] - df_sales_amount_by_date['lag_amount']
df_sales_amount_by_date.head(10)


出力
1
2
3
4
5
6
7
8
9
10
11
	sales_ymd	amount	lag_ymd	lag_amount	diff_amount
0 20170101 33723 NaN NaN NaN
1 20170102 24165 20170101.0 33723.0 -9558.0
2 20170103 27503 20170102.0 24165.0 3338.0
3 20170104 36165 20170103.0 27503.0 8662.0
4 20170105 37830 20170104.0 36165.0 1665.0
5 20170106 32387 20170105.0 37830.0 -5443.0
6 20170107 23415 20170106.0 32387.0 -8972.0
7 20170108 24737 20170107.0 23415.0 1322.0
8 20170109 26718 20170108.0 24737.0 1981.0
9 20170110 20143 20170109.0 26718.0 -6575.0

これで完成です。


第42問目: データフレームの行ずらし(2)

P-042: レシート明細データフレーム(df_receipt)の売上金額(amount)を日付(sales_ymd)ごとに集計し、各日付のデータに対し、1日前、2日前、3日前のデータを結合せよ。結果は10件表示すればよい。

まずはdf_receiptsales_ymd列とamount列のみを抽出し、sales_ymdをグルーピングします。その後にamount列に対して合計値を計算し、indexを再割り当てします。
算出方法は以下に示すとおり3パタンあります。どの方法でも構いません。

1
2
3
4
5
6
7
8
9
10
11
12

# パタン1
df_sales_amount_by_date1 = df_receipt[['sales_ymd', 'amount']].groupby('sales_ymd').sum().reset_index()
df_sales_amount_by_date1

# パタン2
df_sales_amount_by_date2 = df_receipt[['sales_ymd', 'amount']].groupby('sales_ymd').amount.sum().reset_index()
df_sales_amount_by_date2

# パタン3
df_sales_amount_by_date3 = df_receipt[['sales_ymd', 'amount']].groupby('sales_ymd').agg({'amount': 'sum'}).reset_index()
df_sales_amount_by_date3
出力
1
2
3
4
5
6
7
8
9
10
11
12
13
14

sales_ymd amount
0 20170101 33723
1 20170102 24165
2 20170103 27503
3 20170104 36165
4 20170105 37830
... ... ...
1029 20191027 37484
1030 20191028 40161
1031 20191029 36091
1032 20191030 26602
1033 20191031 25216
1034 rows × 2 columns

1日前、2日前、3日前のデータを結合させていくことを考えます。

1つずつデータフレームを作成してから結合していってもよいのですが、ここでは少し応用を効かせてfor文を用いて処理を進めます。

iを1〜3で3回ループさせるようにします。

i1の場合、df_sales_amount_by_dateと1行シフトしたdf_sales_amount_by_dateを結合します。

i!=1の場合は、df_lagと2行、3行とシフトしたデータフレームと結合します。

1
2
3
4
5
6
7
for i in range(1, 4):
if i == 1:
df_lag = pd.concat([df_sales_amount_by_date, df_sales_amount_by_date.shift(i)],axis=1)
else:
df_lag = pd.concat([df_lag, df_sales_amount_by_date.shift(i)],axis=1)

df_lag
出力
1
2
3
4
5
6
7
8
9
10
11
12
13
	sales_ymd	amount	sales_ymd	amount	sales_ymd	amount	sales_ymd	amount
0 20170101 33723 NaN NaN NaN NaN NaN NaN
1 20170102 24165 20170101.0 33723.0 NaN NaN NaN NaN
2 20170103 27503 20170102.0 24165.0 20170101.0 33723.0 NaN NaN
3 20170104 36165 20170103.0 27503.0 20170102.0 24165.0 20170101.0 33723.0
4 20170105 37830 20170104.0 36165.0 20170103.0 27503.0 20170102.0 24165.0
... ... ... ... ... ... ... ... ...
1029 20191027 37484 20191026.0 51771.0 20191025.0 28833.0 20191024.0 31868.0
1030 20191028 40161 20191027.0 37484.0 20191026.0 51771.0 20191025.0 28833.0
1031 20191029 36091 20191028.0 40161.0 20191027.0 37484.0 20191026.0 51771.0
1032 20191030 26602 20191029.0 36091.0 20191028.0 40161.0 20191027.0 37484.0
1033 20191031 25216 20191030.0 26602.0 20191029.0 36091.0 20191028.0 40161.0
1034 rows × 8 columns

すると上記のような新たなデータフレームdf_lagを得ることができます。

カラム名を見るとamountという名前のカラムが複数存在します。区別がつかないので、名前を変更します。

列名は1列目から順にsales_ymd, amount, lag_ymd_1, lag_amount_1, lag_ymd_2, lag_amount_2, lag_ymd_3, lag_amount_3に変更します。

1
2
df_lag.columns = ['sales_ymd', 'amount', 'lag_ymd_1', 'lag_amount_1', 'lag_ymd_2', 'lag_amount_2', 'lag_ymd_3', 'lag_amount_3']
df_lag
1
2
3
4
5
6
7
8
9
10
11
12
13
	sales_ymd	amount	lag_ymd_1	lag_amount_1	lag_ymd_2	lag_amount_2	lag_ymd_3	lag_amount_3
0 20170101 33723 NaN NaN NaN NaN NaN NaN
1 20170102 24165 20170101.0 33723.0 NaN NaN NaN NaN
2 20170103 27503 20170102.0 24165.0 20170101.0 33723.0 NaN NaN
3 20170104 36165 20170103.0 27503.0 20170102.0 24165.0 20170101.0 33723.0
4 20170105 37830 20170104.0 36165.0 20170103.0 27503.0 20170102.0 24165.0
... ... ... ... ... ... ... ... ...
1029 20191027 37484 20191026.0 51771.0 20191025.0 28833.0 20191024.0 31868.0
1030 20191028 40161 20191027.0 37484.0 20191026.0 51771.0 20191025.0 28833.0
1031 20191029 36091 20191028.0 40161.0 20191027.0 37484.0 20191026.0 51771.0
1032 20191030 26602 20191029.0 36091.0 20191028.0 40161.0 20191027.0 37484.0
1033 20191031 25216 20191030.0 26602.0 20191029.0 36091.0 20191028.0 40161.0
1034 rows × 8 columns

処理としては概ね完了かと思いますが、NaNと表示されている欠損値の削除を行います。

欠損値の削除は、dropnaメソッドを使えばOK。

1
df_lag.dropna().head(10)
出力
1
2
3
4
5
6
7
8
9
10
11
	sales_ymd	amount	lag_ymd_1	lag_amount_1	lag_ymd_2	lag_amount_2	lag_ymd_3	lag_amount_3
3 20170104 36165 20170103.0 27503.0 20170102.0 24165.0 20170101.0 33723.0
4 20170105 37830 20170104.0 36165.0 20170103.0 27503.0 20170102.0 24165.0
5 20170106 32387 20170105.0 37830.0 20170104.0 36165.0 20170103.0 27503.0
6 20170107 23415 20170106.0 32387.0 20170105.0 37830.0 20170104.0 36165.0
7 20170108 24737 20170107.0 23415.0 20170106.0 32387.0 20170105.0 37830.0
8 20170109 26718 20170108.0 24737.0 20170107.0 23415.0 20170106.0 32387.0
9 20170110 20143 20170109.0 26718.0 20170108.0 24737.0 20170107.0 23415.0
10 20170111 24287 20170110.0 20143.0 20170109.0 26718.0 20170108.0 24737.0
11 20170112 23526 20170111.0 24287.0 20170110.0 20143.0 20170109.0 26718.0
12 20170113 28004 20170112.0 23526.0 20170111.0 24287.0 20170110.0 20143.0



まとめ

本記事は、「【Python】時系列ずらしの方法を学ぶ | データサイエンス100本ノック【問41〜問42 回答】」というテーマでまとめました。

新たに学んだ事項としてはshiftdropnaかと思います。

>> 続きはこちら

なお、データサイエンティストに必要な知識は、Udemyを活用した学習が効率的です。30日間の返金保証、および一流講師へのQ&Aシステムが整ったオンライン学習プラットフォームです。

世界で34万人が受講した以下の講座をご確認ください。

【世界で34万人が受講】データサイエンティストを目指すあなたへ〜データサイエンス25時間ブートキャンプ〜

コメント