この記事では.
ひよっこは、データを加工するときにどれが一番早く処理できるかが想像できない。。
初心者プログラマあるあるのとりあえず動くコード書いて終わるのと違い、レスポンスだけを指標にすれば(コードの可読性は無視、コメントで回避する)正解を探れるだけ良いので今回は時系列の操作を簡単にまとめます。
検証方法
1年分の時系列データを準備して、datetimeをdateに変換する。(型は一時無視)
方法は以下の5通り(並びは私が早いと思う順)
- pandasの標準dtオブジェクト経由
- pandasのapply経由
- 文字列にして固定長で取り出す方法
- loop処理経由
pythonはインタプリタ言語でコンパイル言語より遅いからライブラリを経由しているのに、
わざわざloop処理を使うのは論外に遅いはず。
ライブラリを使っても型があるのを無視して固定長で取り出す方法も遅い、少なくとも型を守るものよりも遅いはず。
applyは汎用関数なので、元のdtオブジェクトを経由できる方法よりは遅い。という感じに考えています。
検証
詳細とまとめに分けます。
詳細には、コードなども記載します。
詳細
事前にデータを準備する。
以下で作成したデータフレームを測定前にコピーして処理時間を測る。
import pandas as pd
ds = pd.date_range("2001-01-01 00:00:00","2001-12-31 23:59:59", freq="min")
df = pd.DataFrame({"datetime": ds})
# 525600件のデータフレーム作成
1.pandasの標準dtオブジェクト経由
%%timeit
df_test["date_dt"] = df_test.datetime.dt.strftime("%Y-%m-%d")
# 2.18 s ± 55.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
2.pandasのapply経由
%%timeit
df_test["date_apply"] = df_test.datetime.apply(lambda x: x.strftime("%Y-%m-%d"))
# 2.03 s ± 34.7 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
3.文字列にして固定長で取り出す方法(先頭10文字を取得、YYYY-mm-dd)
%%timeit
df_test["date_strcut"] = df_test.datetime.apply(lambda x: str(x)[:10])
# 1.28 s ± 50.2 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
4.loop処理経由(ループだけの時間を計測)
%%time
for index,item in df_test.iterrows():
pass
# CPU times: user 10.8 s, sys: 46.6 ms, total: 10.9 s
まとめ
- pandasの標準dtオブジェクト経由
- pandasのapply経由
- 文字列にして固定長で取り出す方法
- loop処理経由
項目 | 実測値 | 予測順位 | 実測順位 |
---|---|---|---|
pandasの標準dtオブジェクト経由 | 2.18 s ± 55.4 ms | 1 | 3 |
pandasのapply経由 | 2.03 s ± 34.7 ms | 2 | 2 |
文字列にして固定長で取り出す方法 | 1.28 s ± 50.2 ms | 3 | 1 |
loop処理経由 | 10.9s(ここはループだけの時間) | 4 | 4 |
ループ処理はループするだけの時間なのに圧倒的に遅い。
意外なのが、正攻法な方法を利用する方が遅かったことです。
文字列操作で別けてしまったほうが早いという結論になりました。
注意
マシンスペックに依存する可能性はあります。1マシンでの計測しかしていません。