のんびりしているエンジニアの日記

ソフトウェアなどのエンジニア的な何かを書きます。

データ分析に役立つメモリ管理・削減方法

Sponsored Links

皆さんこんにちは
お元気ですか。最近自炊が少しずつ捗ってきました。

本日はデータ分析でよく起こる「Memory Error」の対策を書いていこうと思います。
今回のはGPUではなく、CPUです。

そもそもなぜ「Memory Error」と遭遇するのか

大量のデータを解析する、もしくは、大量の特徴量を扱うからです。
または、途中の巨大途中処理が原因で載らなくなったとかですね。
その結果、マシンが落ちることもデータ分析している人が陥るよくあることです。

その場合の処方箋を書いていこうと思います。

メモリ対策

不要な変数のメモリを開放する。

一番シンプルで、もういらないから消してしまえという方式です。
方法は単純です。変数をdelして、ガーベジコレクション(不要なメモリを回収し、空ける方式)を実行することです。

例えば、次の通りです。

import gc
import numpy as np

matrix = np.random.rand((10000, 10000)) # 適当に作成した巨大行列
# (処理)

del matrix #不要になったので削除
gc.collect() # ガーベジコレクションを実行

これにより要らなくなった段階で不要な変数を削除できるため、特にメモリがギリギリの場合に非常に便利です。

可能な限り型の精度を落とす

numpyやpandasを利用すると大半のカラムはfloat64になっていると思います。
しかし、解析する場合、float64で保持する必要はないでしょう。正直、float32もあれば十分です。
そのため、astypeなどでfloat32やそれ以下に状況に応じて削減すれば良いです。
型を判定し、メモリを削減する方式は次の箇所に記載されています。

www.kaggle.com


また、推論結果を保存したいと思ったこともよくあります。
その際にデータが非常に大きいとディスクを圧迫し、ディスクフルの戦いという不毛なことを行わなければなりません。
一つの対策として保存時に精度を落とすことで(float16や32に)ディスクサイズの削減ができます。
float64から16,32へ変換するのはastype(np.float32)とメソッドを実行すれば良いです。

少し特殊な事例ですが、0-1の場合は、255を乗算することで、uint8で管理できます。
メモリが限られている場合(Kernelなど)に利用可能です。

arr = np.random.rand(200000, 5000)
arr = arr * 255
arr = arr.astype(np.uint8)

一度に大量のデータを読まない

そもそも全てのデータを読み込みオンメモリで管理することは難しい場合もあります。
データを全て載せ、管理することを避けるべきです。

例えば、pandasには、chunkと呼ばれるメソッドがあり、そのメソッドを利用することで部分的に順番に読めます。
そのため、部分的に読みつつ、特徴量などを計算しましょう。

reader = pd.read_csv(fname, skiprows=[0, 1], chunksize=50)
for r in reader:
    print (r)

特徴量のみ保存する

一度に大量のデータを読まないに派生します。
特徴量のみ保存しておいて結合する手があります。
例えばログデータだとすれば、大半のログデータは分量が多いです。

部分的に読むのに加え、特徴量の計算をしておけば全てのデータをメモリで持つことはなくなります。
部分的に読み進め、特徴量を計算し、保存しておくことで、効率化できるでしょう。

最後に

メモリに載らないデータを扱うのはよくあることです。
そのため、このような方法を使ってうまく扱えるようになってもらえると幸いです。