K_DM Book
用語集
対象者 標準
対象者別の入口 →

対象者の設定はこのブラウザの中にだけ保存されます。

言語 JA

処理の進捗を表示

01.5.2

処理の進捗を表示

最終更新 2020-02-12 読了時間 2 分
まとめ
数十万行の DataFrame に apply で 1 行ずつ関数を掛けると、終わるまで何分かかるのか見えないまま待つことになります。tqdm.pandas() を一度呼ぶと Series と DataFrame に progress_apply メソッドが追加され、apply をそれに置き換えるだけで 100%|████| 100/100 [00:01<00:00, 78.99it/s] のようなバーが出ます。表示には処理済み件数、経過時間、残り時間の見積もり、1 秒あたりの件数が含まれるので、途中で中断するか待つかを判断できます。このページでは sleep でわざと時間のかかる関数を 100 行に掛けて、バーが進む様子を確かめます。

直感 #

df["人口総数"].apply(f) は 1 行ずつ f を呼ぶだけなので、全体の行数と「今何行目か」が分かれば残り時間は割り算で出ます。tqdm はこの数え上げを肩代わりする薄い包み紙で、progress_apply は内部で apply を呼びながら 1 件ごとにカウンタを進め、経過時間から残り時間を見積もって表示します。計算そのものは apply と同じなので、結果の DataFrame は変わりません。

Due to popular demand we’ve added support for pandas – here’s an example for DataFrame.progress_apply and DataFrameGroupBy.progress_apply:

サンプルデータ #

sample.csv の先頭 100 行だけを使います。行数を 100 に絞るのは、1 行あたり最大 0.02 秒待つ関数を掛けても全体が 1〜2 秒で終わるようにするためです。

1
2
3
4
import pandas as pd

df = pd.read_csv("../data/sample.csv")[:100]
df.head()

元号和暦西暦人口総数町名
0大正9.01920.0394748A町
1大正9.01920.031421B町
2大正9.01920.0226993C町
3大正9.01920.0253689D町
4大正9.01920.0288602E町

処理の進捗を表示する #

rand_with_sleep(x: int) は 0〜0.02 秒のランダムな時間だけ sleep して、待った秒数を文字列で返す「時間のかかる処理」の代わりです。これを df["人口総数"] の 100 行に progress_apply で掛けると、各行の値が待機秒数に置き換わり、その間コンソールにプログレスバーが伸びていきます。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
import numpy as np
from time import sleep
from tqdm import tqdm

tqdm.pandas()

def rand_with_sleep(x: int) -> float:
    rnd = np.random.rand() / 50.0
    sleep(rnd)
    return f"{rnd} sec"

df["人口総数"] = df["人口総数"].progress_apply(lambda x: rand_with_sleep(x))
df.head()
100%|█████████████████████████████████████| 100/100 [00:01<00:00, 78.99it/s]

元号和暦西暦人口総数町名
0大正9.01920.00.00290391291282283 secA町
1大正9.01920.00.015489350572629845 secB町
2大正9.01920.00.007857787674584393 secC町
3大正9.01920.00.016366338258575495 secD町
4大正9.01920.00.017993046099223576 secE町

使いどころと落とし穴 #

progress_apply が効くのは 1 行ずつ Python の関数を呼ぶ apply 系の処理で、df["人口総数"] * 2 のようなベクトル演算は一瞬で終わるためバーを付ける意味がありません。groupby(...).progress_apply にすればグループ数を分母にしたバーが出て、集計関数の進み具合も追えます。ログをファイルに流す環境では、バーの書き換えがキャリッジリターンの行として大量に残るので、tqdm.pandas(disable=True) か mininterval=5 で更新頻度を落とします。