LoginSignup
1
2

More than 5 years have passed since last update.

pd.tseries.offsets.DateOffset は注意して使わないとかなり遅いことがある

Posted at

言いたいこと

pd.tseries.offsets.DateOffset.__mul__ は使わない方が良い。

経緯

pandasでは、日時を扱うためにpd.Timestamp というクラスが用意されています。また、ある日時からある期間離れた日時を計算したい時は pd.tseries.offsets.DateOffset を使います。
今回は、pd.tseries.offsets.DateOffsetの面白い振る舞いを紹介します。

まずは、以下の実行結果を見てください。

$ python -m timeit -u msec -n 10 -s "import pandas as pd" "pd.Timestamp('2010-01-01 00:00:00') + 100 * pd.tseries.offsets.DateOffset(seconds=1)"
10 loops, best of 3: 0.438 msec per loop
$ python -m timeit -u msec -n 10 -s "import pandas as pd" "pd.Timestamp('2010-01-01 00:00:00') + 1000 * pd.tseries.offsets.DateOffset(seconds=1)"
10 loops, best of 3: 3.85 msec per loop
$ python -m timeit -u msec -n 10 -s "import pandas as pd" "pd.Timestamp('2010-01-01 00:00:00') + 10000 * pd.tseries.offsets.DateOffset(seconds=1)"
10 loops, best of 3: 41.9 msec per loop

何が言いたいかわかりますか?
DateOffsetに掛け算しただけ実行時間が線形に増えています。
多分ですが、内部で pd.Timestamp.__add__ が掛け算した回数だけ呼ばれています。

同じことをやるにはこうすると良いです。

$ python -m timeit -u msec -n 10 -s "import pandas as pd" "pd.Timestamp('2010-01-01 00:00:00') + pd.tseries.offsets.DateOffset(seconds=1*100)"  
10 loops, best of 3: 0.0328 msec per loop
$ python -m timeit -u msec -n 10 -s "import pandas as pd" "pd.Timestamp('2010-01-01 00:00:00') + pd.tseries.offsets.DateOffset(seconds=1*1000)"   
10 loops, best of 3: 0.0373 msec per loop
$ python -m timeit -u msec -n 10 -s "import pandas as pd" "pd.Timestamp('2010-01-01 00:00:00') + pd.tseries.offsets.DateOffset(seconds=1*10000)"
10 loops, best of 3: 0.0336 msec per loop

高速(というか、直感的に当たり前の挙動)になりました。

ちなみに、python標準モジュールのdatetimeを使うとこうなります。非常に高速です。

$ python -m timeit -u msec -n 10 -s "import datetime" "datetime.datetime(2010,1,1) + 100 * datetime.timedelta(seconds=1)"
10 loops, best of 3: 0.0031 msec per loop
$ python -m timeit -u msec -n 10 -s "import datetime" "datetime.datetime(2010,1,1) + 1000 * datetime.timedelta(seconds=1)"
10 loops, best of 3: 0.00276 msec per loop
$ python -m timeit -u msec -n 10 -s "import datetime" "datetime.datetime(2010,1,1) + 10000 * datetime.timedelta(seconds=1)"
10 loops, best of 3: 0.00227 msec per loop
1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2