PythonでExcelの巨大ファイルを扱う際に1000倍高速化する方法(2/2)

入門/解説

1.PythonでExcelの巨大ファイルを扱う際に1000倍高速化する方法(2/2)まとめ

・joblibを使用するとファイルを並列で読み込み速度アップできる
・pickle形式でファイルを保存するとCSVより更に高速になる
・joblibでParallelにprefer=”threads”を指定すると更に高速化できる場合がある

2.pythonで複数ファイルを並列で読み込む方法

以下、www.kdnuggets.comより「Do You Read Excel Files with Python? There is a 1000x Faster Way」の意訳です。元記事は2021年9月、Nicolas Vandeputさんによる投稿です。

アイキャッチ画像のクレジットはPhoto by Hidde van Esch on Unsplash

アイデア#4:Joblibを使用してCSVインポートを並列化する

Pythonで10個のファイルをロードしたい時、各ファイルを1つずつロードするのではなく、すべてを一度に並行してロードしてみませんか?

joblibを使用してこれを簡単に行うことができます。


start = time.time()

def loop(file_number):
  return pd.read_csv(f"Dummy {file_number}.csv")

df = Parallel(n_jobs=-1, verbose=10)(delayed(loop)(file_number) for file_number in range(10))
df = pd.concat(df, ignore_index=True)
end = time.time()
print("CSV//:", end - start)

Joblibを使用してPythonでCSVファイルを並列にインポートします。

これは、シングルコアバージョンのほぼ2倍の速度です。ただし、原則として、8コアを使用してプロセスを8倍高速化できるとは期待しないでください。(ここでは、新しいM1チップを使用してMac Airで8コアを使用することで2倍の速度が得られました)。

(訳注:ライブラリのオーバーヘッドがプラスされるせいか無印 Colabで2.0秒でした。なお、ファイル読み込み処理は2分割され、それぞれ1.1秒と1.4秒で終わっています)

Joblibを使用したPythonでの単純な並列化

Joblibは、並列に関数を実行できるようにする単純なPythonライブラリです。実際には、joblibは、各反復処理が異なるスレッドによって実行されることを除いて、リスト内包のように機能します。

以下が例です。


def loop(file_number):
  return pd.read_csv(f"Dummy {file_number}.csv")

df = Parallel(n_jobs=-1, verbose=10)(delayed(loop)(file_number) for file_number in range(10))

#equivalent to
df = [loop(file_number) for file_number in range(10)]

joblibはスマートなリスト内包と考えてください。

アイデア#5:Pickleファイルを使用する

.csvファイルではなく、pickleファイル(Pythonで良く使用されるファイル保存形式)にデータを保存することで、(はるかに)高速に処理できます。

短所:Pickleファイルをエディターなどで開いて、その内容を直接確認/編集することはできません。


start = time.time()

def loop(file_number):
  return pd.read_pickle(f"Dummy {file_number}.pickle")

df = Parallel(n_jobs=-1, verbose=10)(delayed(loop)(file_number) for file_number in range(10))
df = pd.concat(df, ignore_index=True)
end = time.time()
print("Pickle//:", end - start)

実行時間を80%短縮しました!(訳注:無印 Colabで0.9024秒でした。)

一般に、Pickleファイルの操作はcsvファイルよりもはるかに高速です。ただし、その一方で、picklesファイルは通常、より多くのディスク容量を使用します。(今回の例だけではありません)

また実際には、Excel等の他システムからPickleファイル形式で直接データを保存することはできません。

以下の2つのケースでPickleを使用することをお勧めします。

(1)(Excelでこのファイルを開く予定がない場合に)Pythonのデータを保存して、後で/別のプロセスで使用したいと考えている時、データフレームを.csvではなくPickle形式で保存します

(2)同じファイルを複数回リロードする必要がある場合。
初めてファイルを開くときは、Pickleとして保存して、次回Pickleバージョンを直接ロードできるようにします。
例:トランザクションの月次データを使用するとします。(毎月、新しい月のデータをロードします)。すべての履歴データを.pickleとして保存できます。また、新しいファイルを受信するたびに、そのファイルを.csvとして一度ロードし、次回のために.pickleとして保持することができます。

ボーナス:Excelファイルを並行してロードする

Excelファイルを受け取ったとしましょう。その場合、それらをそのままロードする以外に選択肢はありません。 joblibを使用してこれを並列化することもできます。 上記のpickleコードと比較すると、ループ関数を更新するだけで済みます。


start = time.time()

def loop(file_number):
  return pd.read_excel(f"Dummy {file_number}.xlsx")

df = Parallel(n_jobs=-1, verbose=10)(delayed(loop)(file_number) for file_number in range(10))
df = pd.concat(df, ignore_index=True)
end = time.time()
print("Excel//:", end - start)

Pythonで並列化を使用してExcelファイルをロードする方法

読み込み時間を70%短縮できました(50秒から13秒に)。
(訳注:無印 Colabで45秒->38秒でした。)

このループを使用して、pickleファイルをその場で作成することもできます。そのため、次にこれらのファイルをロードするときに、非常に高速なロード時間を実現できます。


def loop(file_number):
  temp = pd.read_excel(f"Dummy {file_number}.xlsx")
  temp.to_pickle(f"Dummy {file_number}.pickle")
  return temp

要約

pickleファイルを並行してロードすることにより、ロード時間を50秒から10分の1秒未満に短縮しました。

Excel:50秒
CSV:0.63秒
よりスマートなCSV:0.62秒
並行で動かすCSV:0.34秒
並行で動かすpickle:0.07秒
並行で動かすExcel:13.5秒

更にボーナス#2:4倍高速な並列化

Joblibを使用すると、並列化バックエンドを変更して、いくつかのオーバーヘッドを取り除くことができます。 これを行うには、Parallelにprefer=”threads”を指定します。


def loop(file_number):
  return pd.read_pickle(f"Dummy {file_number}.pickle")

df = Parallel(n_jobs=-1, verbose=0, prefer="threads")(delayed(loop)(file_number) for file_number in range(10))
df = pd.concat(df, ignore_index=True)

Preferred =”threads”を使用すると、プロセスをさらに高速に実行できます。

約0.0096秒の実行速度が得られます(2021 MacBook Airで50回以上実行)。CSVおよびExcel並列化でPreferred =”threads”を使用すると、次の結果が得られます。

Parallel Parallel(Thread)
Excel 16.54 51.07
CSV 0.43 0.26
Pickles 0.07 0.01

ご覧のとおり、「threads」バックエンドを使用すると、Excelファイルを読み取るときに逆に時間がかかるようになります。しかし、pickleを使用すると驚くべきパフォーマンスが得られます。(Excelファイルを1つずつロードするのには50秒かかりますが、並列でpickleファイルをスレッドで読み取るとわずか0.01秒です)。

LinkedInで私とつながりましょう!

略歴:Nicolas Vandeputは、需要予測と在庫最適化を専門とするサプライチェーンデータサイエンティストです。

3.PythonでExcelの巨大ファイルを扱う際に1000倍高速化する方法(2/2)関連リンク

1)www.kdnuggets.com
Do You Read Excel Files with Python? There is a 1000x Faster Way

タイトルとURLをコピーしました