Python Excel操作 逆引き集 | チャンクで読み込む(大ファイル)

Python Python
スポンサーリンク

「一気に全部読まない」という武器を持つ

行数が何十万、何百万あるExcelを、read_excel で一気に読み込もうとすると、メモリがパンパンになって固まる——これはよくあるパターンです。
そこで出てくる発想が「チャンク(かたまり)で少しずつ読む」です。

iterator=True, chunksize=10000 を指定すると、
「1回に1万行ずつ読み進める“読み取り専用ジェネレータ”」のようなものが手に入ります。
これをループで回しながら、チャンクごとに集計・加工していくイメージです。


基本形:iterator=True, chunksize=10000 の挙動を理解する

最小コードと「チャンク」のイメージ

import pandas as pd

reader = pd.read_excel(
    "huge_sales.xlsx",
    iterator=True,
    chunksize=10000
)

print(type(reader))  # TextFileReader 的なイテレータ
Python

ここで reader は DataFrame ではなく、「チャンクを順番に返してくれるオブジェクト」になります。
for で回すと、1回のループごとに「最大1万行の DataFrame」が渡されます。

for i, chunk in enumerate(reader, start=1):
    print(f"=== チャンク {i} ===")
    print(chunk.shape)
Python

このとき、ファイル全体は決して一度にメモリに載りません。
常に「今のチャンク」だけを持ちながら処理していく、というスタイルになります。


典型パターン:全体の集計をチャンクで行う

例:金額列の合計を、チャンクをまたいで計算する

巨大な売上ファイル huge_sales.xlsx があり、Amount 列の合計だけ知りたいとします。

import pandas as pd

reader = pd.read_excel(
    "huge_sales.xlsx",
    usecols=["Amount"],
    iterator=True,
    chunksize=10000
)

total = 0

for chunk in reader:
    chunk["Amount"] = pd.to_numeric(chunk["Amount"], errors="coerce")
    total += chunk["Amount"].sum()

print("合計金額:", total)
Python

ここで重要なのは、「チャンクごとに部分合計を出して、最後に足し合わせている」ことです。
どの時点でもメモリ上にあるのは「1万行程度の DataFrame」だけなので、
100万行でも1000万行でも、理論上は同じパターンで処理できます。


条件付き集計やフィルタもチャンクでできる

例:特定期間・特定店舗だけの売上合計を出す

import pandas as pd

reader = pd.read_excel(
    "huge_sales.xlsx",
    usecols=["Date", "Store", "Amount"],
    parse_dates=["Date"],
    iterator=True,
    chunksize=10000
)

target_total = 0

for chunk in reader:
    chunk["Amount"] = pd.to_numeric(chunk["Amount"], errors="coerce")
    mask = (
        (chunk["Date"] >= "2025-01-01") &
        (chunk["Date"] < "2025-04-01") &
        (chunk["Store"] == "Tokyo")
    )
    target_total += chunk.loc[mask, "Amount"].sum()

print("2025年1〜3月 Tokyo 店の売上合計:", target_total)
Python

ここでも、「チャンクごとにフィルタ → 部分合計 → 最後に足し合わせる」という流れです。
全件を一度に DataFrame に載せる必要はありません。


チャンクで「結果だけを貯める」パターン

例:チャンクごとに月次集計して、最後に結合する

「全行を1つの DataFrame にする必要はないけれど、月次集計の結果は欲しい」という場合は、
チャンクごとに集計して、その結果だけをリストに貯めていきます。

import pandas as pd

reader = pd.read_excel(
    "huge_sales.xlsx",
    usecols=["Date", "Amount"],
    parse_dates=["Date"],
    iterator=True,
    chunksize=10000
)

summary_list = []

for chunk in reader:
    chunk["Amount"] = pd.to_numeric(chunk["Amount"], errors="coerce")
    chunk["month"] = chunk["Date"].dt.to_period("M")
    s = (
        chunk.groupby("month", as_index=False)["Amount"]
             .sum()
    )
    summary_list.append(s)

summary = pd.concat(summary_list, ignore_index=True)
summary = summary.groupby("month", as_index=False)["Amount"].sum()

print(summary)
Python

ここでのポイントは、

チャンクごとに「月ごとの部分集計」を作る
部分集計だけを結合する
最後にもう一度まとめて集計して、最終結果にする

という二段階集計です。
元データ全体を一度に持たなくても、集計結果だけなら十分小さく保てます。


iterator=True, chunksize を使うときの設計のコツ

「最終的に欲しいものは何か?」を先に決める

チャンク処理では、「全部の行を DataFrame にしたい」という発想は一度捨てた方がいいです。
代わりに、

合計が欲しいのか
件数が欲しいのか
月次・店舗別などの集計表が欲しいのか

を先に決めて、そのために「チャンクごとに何を計算しておけばいいか」を設計します。

チャンクサイズは「メモリと相談して決める」

chunksize=10000 は一つの目安ですが、
マシンのメモリや列数によっては 5000 や 20000 の方が良いこともあります。

最初は小さめ(例: 5000)で試してみて、
処理が軽そうなら少しずつ増やしていく、という調整の仕方がおすすめです。


実践テンプレート

テンプレ1:巨大ファイルの「行数」と「金額合計」だけ知りたい

import pandas as pd

reader = pd.read_excel(
    "huge_sales.xlsx",
    usecols=["Amount"],
    iterator=True,
    chunksize=20000
)

total_rows = 0
total_amount = 0

for chunk in reader:
    total_rows += len(chunk)
    chunk["Amount"] = pd.to_numeric(chunk["Amount"], errors="coerce")
    total_amount += chunk["Amount"].sum()

print("総行数:", total_rows)
print("金額合計:", total_amount)
Python

「全体像をざっくり知りたい」ときの、最小限チャンク処理テンプレートです。

テンプレ2:巨大ファイルから「条件に合う行だけ」を別ファイルに書き出す

import pandas as pd

reader = pd.read_excel(
    "huge_sales.xlsx",
    usecols=["Date", "Store", "Amount"],
    parse_dates=["Date"],
    iterator=True,
    chunksize=10000
)

first = True

for chunk in reader:
    chunk["Amount"] = pd.to_numeric(chunk["Amount"], errors="coerce")
    mask = (
        (chunk["Date"] >= "2025-01-01") &
        (chunk["Date"] < "2025-02-01") &
        (chunk["Store"] == "Osaka")
    )
    filtered = chunk.loc[mask]

    if filtered.empty:
        continue

    mode = "w" if first else "a"
    header = first
    filtered.to_excel("osaka_2025_01.xlsx", index=False, header=header, mode=mode)
    first = False
Python

ここでは、「条件に合う行だけを、チャンクごとに抽出して追記保存する」というパターンを示しています。
巨大ファイルから「一部だけ切り出して別ファイルにする」用途でよく使います。


小さな練習問題

練習1:huge_sales.xlsx の Amount 合計をチャンクで計算する

条件は次の通りです。

  1. iterator=True, chunksize=10000 で読み込む
  2. 各チャンクで Amount を数値化し、部分合計を足していく
  3. 最後に合計を表示する

まずはこのパターンを手で書いて、チャンク処理の感覚を掴んでみてください。

練習2:huge_sales.xlsx の「2025年だけの月次売上」をチャンクで集計する

条件は次の通りです。

  1. Dateparse_dates で日付型にする
  2. チャンクごとに「2025年の行だけ」に絞る
  3. チャンクごとに月次集計をしてリストに貯める
  4. 最後にそれらを結合して、2025年の月次売上表を作る

ここまでできると、「巨大Excelをチャンクで扱う設計力」がかなり身についてきます。


最後に

iterator=True, chunksize=10000 は、
「メモリに優しい読み方に切り替えるスイッチ」です。

全部を一気に読むのではなく、
「チャンクごとに処理して、欲しい情報だけを積み上げる」という発想に切り替えると、
これまで「重くて無理」と感じていたサイズのファイルとも、ちゃんと対話できるようになります。

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