pythonのベンチマークツール『perfplot』『benchit』の使い方
pythonのベンチマークツール、perfplotとbenchitの使い方のざっくり解説です。
どちらのライブラリも、主に「pd.DataFrame
およびnp.ndarray
を整形する複数の関数の実行速度の比較」のために作られました。これらのツールを使うと、「横軸に整形する対象のpd.DataFrame
およびnp.ndarray
の長さ、縦軸に各関数の実行速度」をとった折れ線グラフを簡単に作ることができます。
もちろん、pd.DataFrame
およびnp.ndarray
以外を受け取る関数に対しても使うことができます。
0. 例題
pandas小技: 複数の文字列のいずれかを含む (OR + 部分一致) 検索したい - け日記より。
例えば↓のテーブルから 東京都または千葉県 を含む値だけをフィルタする場合に、pandasではどう書くかです。
name 0 東京都葛飾区 1 神奈川県川崎市 2 埼玉県蕨市 3 千葉県蘇我市
import pandas as pd
df = pd.DataFrame({'name': ['東京都葛飾区', '神奈川県川崎市', '埼玉県蕨市', '千葉県蘇我市']})
function(df)
name 0 東京都葛飾区 3 千葉県蘇我市
となる関数を作る。
いろいろな方法が考えられる。
def by_contains(df):
idx = df['name'].str.contains(r'東京都|千葉県')
return df[idx]
def by_startswith(df):
idx = df['name'].str.startswith('東京都') | df['name'].str.startswith('千葉県')
return df[idx]
def by_str_startswith(df):
idx = [s.startswith('東京都') or s.startswith('千葉県')
for s in df['name'].tolist()]
return df[idx]
def by_np_isin(df):
idx = np.isin(df['name'].to_numpy('<U3'), ['東京都', '千葉県'])
return df[idx]
def by_np_or(df):
arr = df['name'].to_numpy('<U3')
idx = (arr == '東京都') | (arr == '千葉県')
return df[idx]
さてここで、これらの関数のどれが最も速いのか?
1. perfplotの使い方
GitHub - nschloe/perfplot: Performance plots for Python code
pip install perfplot
でインストール。
時間計測方法
時間計測にはperfplot.bench()
関数を用いる。測定結果としてPerfplotData
オブジェクトが返ってくる。
以下は必須パラメータ。
setup
引数:「整数を1つ受け取って「計測したい関数に渡すインプットデータ」を作る関数」を渡す。データフレームの場合は、サンプルとして小さいdf
を作った後に以下を渡す事が多い。
lambda n: df.sample(n, replace=True, random_state=0).reset_index(drop=True)
lambda n: pd.concat([df]*n, ignore_index=True, axis=0)
n_range
引数:setup
関数にわたすn
の数のリストを渡す。10 ** np.arange(5)
とかでOK。
kernels
引数:計測したい関数のリストを渡す。
equality_check
引数:True
/False
を返す関数を指定して、各関数が等しい結果を返しているかどうかを確認し、異なる結果を返している場合はエラーを出す。以下のどれかでOK。
- 関数の結果が等しいかどうかを比較しない場合:
None
-
pd.DataFrame
を返す関数の結果が等しいかどうかを比較する場合:lambda df1, df2: df1.equals(df2)
-
np.ndarray
を返す関数の結果が等しいかどうかを比較する場合:np.allclose
(デフォルト)
以下はオプションのパラメータ。
labels
引数:グラフに表示する関数名のリスト。kernels
に渡したリストと同じ長さであること。指定しない場合は関数名がそのまま使われる。
xlabel
引数:横軸(n
)のラベル名。
プロット出力方法
PerfplotData.show()
メソッドで実行時間を比較した折れ線グラフを表示する。
また、PerfplotData.save()
メソッドでプロットを画像として保存する。
実行例
import numpy as np
import perfplot
ppdata = perfplot.bench(
setup=lambda n: df.sample(n, replace=True, random_state=0).reset_index(drop=True),
n_range=10 ** np.arange(7),
kernels=[
by_contains,
by_startswith,
by_str_startswith,
by_np_isin,
by_np_or
],
equality_check=lambda df1, df2: df1.equals(df2),
xlabel='len(df)'
)
ppdata.save('perfplot.png', time_unit='s')
PerfplotData.save()
メソッドのrelative_to
引数に、kernels
引数に渡したリストに対応する整数インデックスを与えると、縦軸が相対速度になる。
ppdata.save('perfplot2.png', time_unit='s', relative_to=2)
2. benchitの使い方
GitHub - droyed/benchit: Benchmarking tools for Python
pip install benchit
でインストール。
時間計測方法
時間計測にはbenchit.timings()
関数を用いる。測定結果としてBenchmarkObj
オブジェクトが返ってくる。
以下は必須パラメータ。
funcs
引数:計測したい関数のリストを渡す。perfplotのkernels
引数と同じ。
inputs
引数:計測したい関数に渡すインプットデータのリストを渡す。perfplotのsetup
とn_range
引数に該当する。
プロット出力方法
BenchmarkObj.plot()
メソッドでmatplotlib.figure.Figure
オブジェクトが返されるので、受け取ったFigure
オブジェクトの.show()
メソッドおよび.savefig()
メソッドでプロットの出力・保存が可能。
実行例
import numpy as np
import benchit
funcs = [
by_contains,
by_startswith,
by_str_startswith,
by_np_isin,
by_np_or
]
inputs = [df.sample(n, replace=True, random_state=0).reset_index(drop=True)
for n in 10 ** np.arange(7)]
bmobj = benchit.timings(funcs, inputs)
bmobj.plot(figsize=(10, 6), logx=True).savefig('benchit.png')