Skip to content

Polarsのgroup_by_dynamicが便利

Polarsのgroup_by_dynamic1が便利だったので紹介する。というかPolarsが便利。

Polars

株価のデータの日次データを月次データに変換するコードを例にする。

import yfinance as yf
import polars as pl

df_pandas = yf.download('7203.T', start="2000-01-01", end="2020-12-31").reset_index()
(
    pl.DataFrame(df_pandas).sort('Date')
    .group_by_dynamic(index_column='Date', every='1mo', label='datapoint')
    .agg([
        pl.col('Date').first().alias('Month_Start'),
        pl.col('Date').last().alias('Month_End'),
        pl.col('Open').first(),
        pl.col('High').max(),
        pl.col('Low').min(),
        pl.col('Close').last(),
        pl.col('Volume').sum()
    ])
    # .drop(columns=['Date'])
)
Alt text

label='datapoint'の引数を指定することで、indexに指定したDateの中に存在する値の中で初出の値を利用していることが確認できる。個人的にはpandasで実装していたときに欲しかった機能だったので嬉しい。今回の場合はMonth_StartMonth_Endのcolumnを作成しているので.drop(columns=['Date'])することになるので関係ないかもだが。

Pandas

別にpandasでもできるけど、ダブルコラムになったりして面倒だったりする(と私は思っている)。 あと、pandasのaggの使い方が少しわかりづらいな、とも思っている。

(
    df_pandas
    .groupby(pd.Grouper(key='Date', freq='M'))
    .agg({
        'Open': 'first',
        'High': 'max',
        'Low': 'min',
        'Close': 'last',
        'Volume': 'sum',
        'Date': ['first', 'last']
    })
)
Alt text このように、indexがDateになっているが、このindexは月終わりの日付になっている。実際にはこの日が土日になったりするので、Datelastとはずれることがある。実際にはreset_index等を呼び出してindex周りの整理をすることになると思う。このあたりはPolarsの方が好みだな、と感じている。そもそもPolarsにはindexがないので、このような問題は起こらない。また、ダブルコラムに対応するために、column周りの整理も行うことになる。このあたりもPolarsでは.alias('hoge')で簡単に処理ができるのが嬉しい。

ちなみにpandasのgroupbyの引数にdf_pandas['Date'].dt.to_period('M')を指定すると、indexを月次にすることができる。polarsにはto_periodのようなメソッドはないのが残念ではある。

(
    df_pandas
    .groupby(df_pandas['Date'].dt.to_period('M'))
    .agg({
        'Open': 'first',
        'High': 'max',
        'Low': 'min',
        'Close': 'last',
        'Volume': 'sum',
        'Date': ['first', 'last']
    })
)
Alt text

まとめ

今年はpandasからpolarsに改宗します。