Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Polarsで始める時系列データ処理 #atmaCup 19 振り返り会 LT枠

Kohei Iwamasa
April 11, 2025
290

Polarsで始める時系列データ処理 #atmaCup 19 振り返り会 LT枠

Kohei Iwamasa

April 11, 2025
Tweet

Transcript

  1. 集約と結合 • Polarsでは group_by でグループごとに計算することができます • 集約したテーブルをもとに join でデータフレームどうしを結合しましょう group_df

    = df.group_by("ユーザー").agg(pl.col("購入金額").mean().alias("平均購入金額 ")) df.join(group_df, on="ユーザー", how="left") 集約データ join
  2. Nステップ前の⾏動を抽出する • shift と over を⽤いることでグループごとにスライドすることができます ◦ pandasだとこういう処理: df.groupby("ユーザー")["購入金額"].shift(1) df.with_columns(pl.col("購入金額").shift(1).over("ユーザー").name.prefix("shift1_"))

    • データの並び順に要注意!sort を忘れずに • over を使った便利メソッドは以下: ◦ diff ◦ cum_sum ◦ cum_count ... Nステップ前との差分 ... これまでの累積和 ... これまでの出現数 など
  3. Datetime型の列間で⽐較する • Datetime型を⽐較 (差) を取るとその差で Duration型 に変換されます df.with_columns((pl.col("売上日") - pl.col("売上日").shift(1).over("ユーザー")).alias("間隔"))

    • pl.col("売上日").diff(1).over("ユーザー") も同様 • Duration型からfloat型に変換する場合は pl.duration(days=1) などで割ると👍 ◦ そのままだと μs 単位で値が⼤きくなるため df.with_columns((pl.col("間隔") / pl.duration(days=1)) pl.duration (days=1)で割る pl.col("売上日") + pl.duration(hours=pl.col("時刻")) • Datetime型 に時刻を⾜すことも可能
  4. 時間を考慮しない移動平均 • rolling_mean でNステップ前までの値を平均値を抽出できます df.with_columns( pl.col("購入金額").rolling_mean(window_size=3).over("ユーザー").name.prefix("移動平均_") ) min_samples=3 min_samples=2 min_samples=1

    • min_samples を指定可能 → • weights を引数に渡すことで 重み付き平均を計算することも可能 • min, max, median, stdなど 他の集約も可能 (e.g., rolling_min)
  5. 時間を考慮する移動平均 • rolling を使うことで時間を考慮した集約が可能です df.rolling(index_column="売上日", group_by="ユーザー", period="1mo") \ .agg(pl.col("購入金額").mean().name.prefix("移動平均_")) •

    index_column はDatetime型の列、 group_by はグループの列を指定します • period で範囲を指定することができます ◦ 1d は1⽇、2w は2週間 など • 元の並び順がシャッフルされた異なる データフレームが返されます ◦ そのまま横結合するとダメ (1敗)
  6. 時間を考慮する移動平均 - 重複を排除した結合 • rolling 後のデータフレームの重複した⾏を削除する必要がある • 重複した⾏は unique で削除可能!

    rolling_df.unique(subset=["ユーザー", "売上日"]) 元のテーブル join 後のテーブル 👏 rolling 後のテーブル left join (売上日,ユーザー)
  7. 時間を考慮する移動平均 - offsetの指定 • rolling は period の他 offset を引数に加えることで挙動が変わる

    • period も offset も同じ⽂字列⽅式で、offset はマイナスの指定も可能 https://docs.pola.rs/api/python/stable/reference/dataframe/api/polars.DataFrame.rolling.html offsetがNoneの場合は、 period遡った時刻から現時刻までを集約 offsetが指定された場合は、 現時刻からoffset分加算された時間から offsetとperiod分加算された時間までを集約
  8. 時間を考慮する移動平均 - offsetの指定の例 • 2週間前から1週間前までの集約する場合: df.rolling(index_column="売上日", group_by="ユーザー", period="1w", offset="-2w") •

    1週間前から1週間先までの集約する場合: df.rolling(index_column="売上日", group_by="ユーザー", period="2w", offset="-1w") • rolling は closed を設定することで条件に重なる箇所を含めるか変更可能 ◦ offset も None, closedも"none" に設定することで現時刻を含めない処理!
  9. 時系列を考慮したTarget Encoding (ベイズ推定) • クルトンさんのベイズ推定によるシンプルな推論を Target Encodingの代わりに使うことで精度改善! ◦ CatBoostのTarget Encodingとほぼ⼀緒!

    TE 検証スコア Public LB Private LB リークなし 0.7760 0.7553 0.7500 ベイズ推定 0.7849 0.7607 0.7562 • コードはこちらに! https://www.guruguru.science/competitions/26/discussions/054b216b-2375-4608-9e2d-ee2a655049e4/