【前編】Pythonで日付や id を含むデータの特徴量の作成についてまとめてみた

公開:2021/01/29
更新:2021/02/08
4 min読了の目安(約3800字TECH技術記事

日付データが数値データになっている場合の処理を以前ブログにまとめました。

https://zenn.dev/megane_otoko/articles/021_deal_datetime

今回は前後編に分け前編(本ブログ)は時系列の特徴量作成について、後編では日付を含むデータの範囲を絞ったり、IDごとに集計する場合のテクニックをまとめたいと思います。

なお、データはkaggleのM5の下記の2つを使用しています。

  • sales_train_evaluation.csv
  • calendar.csv

加工して下記のようなデータ(文中では dtable )を使用します。

詳細なコードはこちら

なお、ブログ中のdtはdatetimeを表します。

import datetime as dt

時系列の特徴量を作成する

年や月、日といった時系列ならではの特徴量を作成します。

https://qiita.com/ground0state/items/657861de619a4e4a30de
# 年
dtable["year"] = dtable["date"].dt.year

# 月
dtable["month"] = dtable["date"].dt.month

# 日
dtable["day"] = dtable["date"].dt.day

休日かどうか、というフラグを作成してみましょう。

日付データから、土日かどうかを判定するために datetime.deyofweek を使って曜日を、jpholiday ライブラリを使って祝日を割り出します。

祝日を割り出す処理はかなり重いので注意しましょう。

https://github.com/Lalcs/jpholiday
# 曜日 月曜が0, 日曜が6
dtable["dayofweek"] = dtable["date"].dt.dayofweek

# 祝日
dtable["p_holiday"] = dtable["date"].map(jpholiday.is_holiday).astype(int)

# 土日、祝日を1、それ以外を0とする
dtable["holiday"]=0
dtable.loc[(dtable["dayofweek"]==5)|(dtable["dayofweek"]==6)|(dtable["p_holiday"]==1), 'holiday'] = 1

https://upura.hatenablog.com/entry/2018/12/21/070000

また今が1年のうちの何週目かどうかも作成してみましょう。

特徴量として使用するのであれば、数値データとしたほうがよさそうですが、今回は、あとで日ごとのデータを週ごとに集約した後にもタイムスタンプデータを残すため、週番号を日付に変換できるようにしています。

例えば 2018-W1-1 のように、年-W週番号-1 としてやれば、あとで日付データ、すなわちその週番号の月曜日の日付に変換することが可能です。

# 週番号 後で日付に変換できるように、年-W週番号-1 例 2018-W1-1、となるようにする
dtable["numofweek"] = "W" + dtable["date"].dt.strftime("%V").astype(int).astype(str)
dtable["numofweek"] = dtable["year"].astype(str).str.cat(dtable["numofweek"], sep="-") + "-1"

https://www.it-swarm-ja.tech/ja/python/週番号から日付を取得/1073246042/

https://qiita.com/T_Shinomiya/items/ff9d845c6f23fd8f1ba2

出力すると下記のようになります。

また、下記のサイトのように、shift や diff を使って ラグデータを作成するのも有効のようです。

ただし、アイテムID や 店舗IDのあるデータの場合は、少し複雑なテクニックが必要となります。

なお、kaggle のノートブックのため詳細な説明は割愛しますが、GitHubのコードの中でこれらのテクニックを使用していますのでご参照ください。

日ごとのデータを、週単位のデータに集約する

時系列データがあまりに大きすぎるので、日ごとのデータを週ごとのデータに集約してみましょう。

pivot_table を使い、引数の values に集約したい数値データの sales_quantity を、aggfunc に 'sum' を設定すれば、週ごとの合計を算定することができます。

https://deepage.net/features/pandas-pivot.html

なお、pivot_table を使うと、マルチインデックスになってしまい、やや面倒なので .reset_index() を使って解除します。

week_pivot = pd.pivot_table(dtable, values="sales_quantity", 
    index=["numofweek", "weekday", "id", "cat_id", "item_id", "store_id", "year", "month"], aggfunc='sum')

# マルチインデックスを解除
week_pivot = week_pivot.reset_index()

出力すると下記のようになります。

下記サイトのとおりタイムインデックスを使った集計も可能ですが、ID等が数値データだった場合IDまで集約されてしまうので気を付けましょう。

https://note.nkmk.me/python-pandas-time-series-datetimeindex/

https://note.nkmk.me/python-pandas-time-series-multiindex/

集約ができたら、週番号を週番号をその週の月曜日に相当する日付に変換してやります。

# 週番号をその週の月曜日に相当する日付に変換する
week_pivot["startofweek"] = pd.to_datetime(dtable["numofweek"], format="%Y-W%W-%w")

このように、日付データに戻すことができました。

前編は以上になります。

後編では日付を含むデータの範囲を絞ったり、IDごとに集計する場合のテクニックをまとめたいと思います。

以上になります、最後までお読みいただきありがとうございました。

参考サイト

https://oku.edu.mie-u.ac.jp/~okumura/python/datatable.html