01.9.6
巨大なCSVでMemoryErrorになる
MemoryError: Unable to allocate 12.5 GiB for an array with shape (…) は、read_csv が CSV 全体を一度に DataFrame として展開しようとし、PC の空きメモリを超えた、という報告です。CSV は 1 文字 1 バイトですが、pandas は数値を 8 バイトの float64、文字列を Python オブジェクトとして保持するので、ディスク上 3 GB のファイルがメモリでは 10 GB を超えることがあります。対処は chunksize=100_000 で 10 万行ずつ読んで集計する、usecols で必要な 3 列だけ読む、dtype で int32・float32 に落とす、compression="gzip" で解凍せずに読む、の 4 つで、組み合わせるとメモリ使用量を元の 1/4 以下にできます。このページでは big.csv の amount 列の合計を出す例で、それぞれの効き方を示します。直感 #
pd.read_csv("big.csv") は、ファイルを全行読み終えるまで結果を返さず、その間に全列・全行分の配列をメモリに確保します。数値列は 1 セル 8 バイト、文字列列は 1 セル 50 バイト以上を使うので、1 億セルの CSV は数 GB から十数 GB になります。MemoryError を避ける考え方は「一度に持つ量を減らす」ことで、行を分けて持つ(chunksize)、列を減らす(usecols)、1 セルのバイト数を減らす(dtype)、の 3 方向があり、どれも読み込みの引数 1 つで指定できます。
数 GB 以上の CSV を read_csv() で読み込むと、途中で
MemoryError: Unable to allocate XX GiB for an array with shape (…)
と表示されて処理が止まることがあります。メッセージの XX GiB が確保しようとした量、shape が行数と列数で、shape (100000000, 12) なら 1 億行 12 列を一度に持とうとしたことが分かります。ローカル PC の 16 GB では足りないため、分割して読む・不要な列を捨てる・型を最適化する といった工夫が必要です。
解決法 1: チャンク単位で読み込む #
chunksize=100_000 を付けると read_csv は DataFrame ではなくイテレータを返し、for で回すたびに 10 万行分の DataFrame が 1 つ渡されます。合計や件数のように「全行を同時に見なくてよい」集計なら、この 10 万行分のメモリだけで最後まで走れます。
| |
解決法 2: 必要な列だけ読み込む #
分析に使う列が customer_id・amount・created_at の 3 列だけなら、usecols でその 3 列を指定します。12 列のファイルなら読み込み時点でメモリが 1/4 になります。
| |
解決法 3: dtype を先に指定する #
pandas の型推定は安全側に寄っていて、整数は int64(8 バイト)、小数は float64(8 バイト)、文字列は object(50 バイト以上)になります。値の範囲が分かっている列は int32・float32・boolean を dtype で先に伝えると、1 セルあたりのバイト数が半分以下になります。
| |
解決法 4: 圧縮ファイルのまま読み込む #
gzip や zip で圧縮された CSV は、解凍して数 GB のファイルをディスクに置かなくても、compression を指定すればそのまま読めます。ネットワーク越しにダウンロードする場合も、圧縮ファイルのまま read_csv に渡すのが安全です。
| |
使いどころと落とし穴 #
最初に確かめるのは、本当に全列を読む必要があるか(usecols)と、数値列・分類列の型を int32・float32・category に落としたか(dtype)の 2 点で、これだけで 12 列中 3 列・8 バイトから 4 バイトなら使用量は 1/8 になります。それでも入らないなら、合計や件数のように行をまたがない集計は chunksize=100_000 の分割処理に書き換え、中央値や結合のように全量が必要な処理は dask・polars・DuckDB のようにメモリに載せずに動くツールへ移します。読み込み後は df.memory_usage(deep=True).sum() / 1e9 で実際の GB 数を見て、見積もりとの差を確認してください。
参考 #
chunksize・usecols・dtype・compression の詳細は IO Tools (Text, CSV) — pandas documentation に、同じ API でチャンクを並列処理する方法は Dask DataFrame Documentation にあります。