LoginSignup
4
6

More than 3 years have passed since last update.

pythonのベンチマークツール『perfplot』『benchit』の使い方

Posted at

pythonのベンチマークツール『perfplot』『benchit』の使い方

pythonのベンチマークツール、perfplotbenchitの使い方のざっくり解説です。
どちらのライブラリも、主に「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')

perfplot.png

PerfplotData.save()メソッドのrelative_to引数に、kernels引数に渡したリストに対応する整数インデックスを与えると、縦軸が相対速度になる。

ppdata.save('perfplot2.png', time_unit='s', relative_to=2)

perfplot2.png

2. benchitの使い方

GitHub - droyed/benchit: Benchmarking tools for Python

pip install benchitでインストール。

時間計測方法

時間計測にはbenchit.timings()関数を用いる。測定結果としてBenchmarkObjオブジェクトが返ってくる。

以下は必須パラメータ。

funcs引数:計測したい関数のリストを渡す。perfplotのkernels引数と同じ。

inputs引数:計測したい関数に渡すインプットデータのリストを渡す。perfplotのsetupn_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')

benchit.png

4
6
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
4
6