まずは蝋の翼から。

学んだことを書きながら確認・整理するためのメモブログ。こういうことなのかな?といったことをふわっと書いたりしていますが、理解が浅いゆえに的はずれなことも多々あると思うのでツッコミ歓迎

tqdmでプログレスバーを出す

pythontqdmライブラリを試す。

tqdmとは

何かしらの処理に対する進捗をプログレスバーとして表示するライブラリ。

github.com

loop処理

基本的な使い方として、繰り返し処理の1loop毎にプログレスバーを更新することができる。

イメージとしては、通常の繰り返し処理コードに対して全数を表す部分をtqdm関数で囲いこむだけでプログレスバーを作成することができる。

range での繰り返し

import time
import pandas as pd
from tqdm import tqdm

# 通常
for i in range(100):
    time.sleep(0.1)

# tqdm
for i in tqdm(range(100)):
    time.sleep(0.1)

f:id:chito_ng:20200524073935p:plain:w500

list 取り出しでの繰り返し

import time
import pandas as pd
from tqdm import tqdm

# 通常
for i in list([1, 2, 3, 4]):
    time.sleep(1)

# tqdm
for i in tqdm(list([1, 2, 3, 4])):
    time.sleep(1)

f:id:chito_ng:20200524074133p:plain:w500

pandas.apply処理

tqdm.pandas() コードを走らせると、pandas.applyと同じ使い方のままでプログレスバーが表示されるprogress_applyが使えるようになる。
applyは1行(列)毎に関数処理をおこなうメソッドなので、1行(列)処理する毎にプログレスバーが進む。

tqdm.pandas() # progress_applyを取得

df = pd.DataFrame(list(range(10000)))

# 通常
df.apply(lambda x: x ** 2, axis=1)

# tqdm
df.progress_apply(lambda x: x ** 2, axis=1)

f:id:chito_ng:20200524074951p:plain:w500

jupyter notebook用

tqdm_notebookを用いることで、通常のtqdmと同様の処理でjupyte notebook(lab)用の表示ができる。

===========2021/06/16追記============ from tqdm import tqdm_notebookは近々廃止され、from tqdm.notebook import tqdmになるそうです。
てか記事を書いた段階でわかってしかるべきだったが調べた情報が古かったというか、一時ソースで読まないといけないなーと反省(しつつ、参考サイトは二次ソース)。

参考 blog.neko-ni-naritai.com


from tqdm import tqdm # 通常
from tqdm import tqdm_notebook as tqdm_nb # notebook用

# 通常tqdm
for i in tqdm(range(100)):
    time.sleep(0.1)

# notebook用 tqdm
for i in tqdm_nb(range(100)):
    time.sleep(0.1)

f:id:chito_ng:20200524075513p:plain:w500

ただし、progress_apply には対応していなかったり、全く同じ処理ができるわけではないので注意。
notebookに表示すると見づらくなることも多いので、対応してない場合のみtqdmを使う使い分けか?

後述するが、loopが多い場合は1loopが終わる毎にプログレスバーを消しオプションがあるが、tqdmはnotebookだと消えずに全て表示されて、表示が冗長になるのでtqdm_notebookの方が圧倒的に使いやすい。

カスタマイズ

以下の記事を参考にする。
なお、今回notebookを使っているのでtqdm_nbとしているが、説明ではtqdmと表記する。

www.kimoton.com

loopのはじめにtqdmwith指定すると、以降のloop処理が自動でプログレスバーが表示される。

total引数で全体の数を指定できる。update関数を用いることでそのプログレスバーを進めることができる。
プログレスバーの数値は、totalが分母でupdateが分子として計算される。

プログレスバーは、 例えば2重loopの際に各with時にasでそれぞれ名前をつけるとそれぞれ別のプログレスバーとして進捗をチェックすることができる。

また、プログレスバーの前後にある文はそれぞれ set_description, set_postfixで変えることができる。

with tqdm_nb(total=100) as pbar1: #  プログレスバー1
    for i in range(100):
        pbar1.set_description(f'プログレスバー1-{i}') # プログレスバー1の手前の表示文字
        pbar1.set_postfix(progress=i) # プログレスバー1の末尾の表示文字
        pbar1.update(1) # プログレスバー1を1/10進める
        with tqdm_nb(total=100, leave=False) as pbar2: #  プログレスバー1。leaveで100%後に消えるかどうか指定
            for j in range(100):
                pbar2.set_description(f'プログレスバー2-{i}') # プログレスバー2の手前の表示文字
                time.sleep(0.01)
                pbar2.update(1) # プログレスバー2を1/10進める
                pbar2.set_postfix(progress=j) # プログレスバー2の末尾の表示文字

f:id:chito_ng:20200524092404p:plain:w600

なお、1loop内で処理ごとに進捗を進める、例えばloop内で1処理したら1%、次の処理で2%...のようなこともできる。 例えば、機械学習モデルにおいて、各pipeline毎にかかる時間をざっくり先に計算しておき、それぞれでプログレスバーを進めると便利。

with tqdm_nb(total=50) as pbar1:
    for i in range(10):
        pbar1.set_description(f'プログレスバー1-{i}')
        pbar1.set_postfix(progress=i)
        time.sleep(1)
        pbar1.update(1) # プログレスバーを1/50進める
        time.sleep(1)
        pbar1.update(4) # プログレスバー1を4/50進める

参考

blog.amedama.jp

qiita.com