pandas で大きな CSV を chunksize で分割読み込みする

数 GB を超える CSV ファイルを丸ごと読み込もうとすると、メモリ不足でエラーになることがあります。pandas の read_csv には chunksize 引数が用意されており、データを分割して少しずつ処理できます。

chunksize で分割読み込みする

chunksize に行数を指定すると、read_csv は DataFrame ではなくイテレータを返します。

import pandas as pd

chunks = pd.read_csv("large_data.csv", chunksize=10000)

for chunk in chunks:
    print(chunk.shape)

1 万行ずつ DataFrame が生成されるため、メモリには常に 1 チャンク分のデータしか載りません。ファイル全体を一度に読み込む必要がなくなるわけです。

チャンクごとに集計する

分割読み込みでよくあるパターンは、各チャンクで集計して最後にまとめる方法です。

total = 0
count = 0

for chunk in pd.read_csv("large_data.csv", chunksize=10000):
    total += chunk["price"].sum()
    count += len(chunk)

average_price = total / count
print(f"平均価格: {average_price:.2f}")

合計と件数をチャンクごとに積み上げていけば、全データの平均が求められます。メモリを節約しながらも正確な結果が得られるのがこの方法の強みです。

チャンクをフィルタリングして結合する

必要なデータだけを抽出してから結合すれば、メモリ消費を抑えつつ分析対象のデータを手に入れられます。

filtered = []

for chunk in pd.read_csv("large_data.csv", chunksize=10000):
    subset = chunk[chunk["category"] == "electronics"]
    filtered.append(subset)

df = pd.concat(filtered, ignore_index=True)
print(df.shape)

全体が 1000 万行あっても、フィルタ後のデータが数万行に収まるならメモリの問題は発生しません。

chunksize で分割読み込み

各チャンクで必要な処理を実行

結果を集約または結合

usecols と dtype で効率を上げる

chunksize と併用すると効果的なオプションがいくつかあります。

chunks = pd.read_csv(
    "large_data.csv",
    chunksize=10000,
    usecols=["id", "price", "category"],
    dtype={"id": str, "price": float, "category": "category"}
)
usecols必要な列だけを読み込む
dtype列の型を明示して型推定を省略
low_memoryメモリ効率を優先する(デフォルト True)

usecols で不要な列を除外し、dtype で型を明示すれば、チャンクあたりのメモリ消費がさらに小さくなります。特に文字列列を category 型にすると、メモリ使用量を大幅に削減できます。

get_chunk で手動制御する

TextFileReader オブジェクトの get_chunk メソッドを使えば、1 チャンクずつ手動で取得することもできます。

reader = pd.read_csv("large_data.csv", chunksize=10000)
first_chunk = reader.get_chunk()
second_chunk = reader.get_chunk()

for ループで全チャンクを回す必要がなく、最初の数チャンクだけ確認したいときに便利です。

chunksize による分割読み込みは、メモリに載りきらない大規模データを pandas で扱うための基本テクニックです。さらに大きなデータを恒常的に扱うなら、Parquet 形式への変換や Dask の利用も検討するとよいでしょう。