そもそも「インデックス」って何者か
pandas の DataFrame には、左端に「0, 1, 2, …」と並ぶ“行番号”のようなものがあります。
これが インデックス(index) です。
Python の世界ではとても便利な仕組みですが、
Excel に書き出すときには、たいてい「余計な列」に見えます。
index=False は、
「このインデックス列は、Excelには出さなくていいよ」
と pandas に伝えるためのスイッチです。
基本形:to_excel(…, index=False) の挙動
index=True の場合(デフォルト)をまず見る
import pandas as pd
df = pd.DataFrame({
"date": ["2025-01-01", "2025-01-02"],
"product": ["りんご", "みかん"],
"amount": [1000, 800]
})
df.to_excel("with_index.xlsx")
Pythonこのまま書き出すと、Excel はこうなります。
| date | product | amount | |
|---|---|---|---|
| 0 | 2025-01-01 | りんご | 1000 |
| 1 | 2025-01-02 | みかん | 800 |
左端の「0」「1」が、pandas のインデックスです。
コードを書く側には便利ですが、業務で人に渡すファイルとしては、ほぼ不要です。
index=False の場合
df.to_excel("without_index.xlsx", index=False)
Pythonこの場合、Excel はこうなります。
| date | product | amount |
|---|---|---|
| 2025-01-01 | りんご | 1000 |
| 2025-01-02 | みかん | 800 |
左端のインデックス列が消え、
「列=本当に意味のある項目」だけになります。
ここが index=False の一番大事な効果 です。
なぜ index=False を「基本形」にしておいた方がいいのか
人間から見ると「意味のない列」が増えるから
pandas のインデックスは、
「Python の中で行を特定するためのラベル」であって、
「業務上のID」ではありません。
それなのに Excel に出すと、
「なんか左に謎の番号列がある…これ何?」
と、受け取った人を混乱させます。
だから、特別な理由がない限り、Excel出力では index=False を付ける、
これを“デフォルトの癖”にしてしまっていいレベルです。
実務パターン:集計結果をきれいに出す
例:月次集計を Excel に出すとき
import pandas as pd
df = pd.read_excel("sales.xlsx", parse_dates=["日付"])
df["金額"] = pd.to_numeric(df["金額"], errors="coerce")
monthly = (
df.assign(month=df["日付"].dt.to_period("M"))
.groupby("month", as_index=False)["金額"].sum()
)
monthly.to_excel("sales_monthly.xlsx", index=False)
Pythongroupby(..., as_index=False) にしているので、monthly のインデックスはただの 0,1,2,… です。
ここで index=False を付けておけば、
Excel には「month」「金額」だけが出力され、
そのまま人に渡せるきれいな表になります。
ExcelWriter と組み合わせるときも同じ
複数シートを書き出すときの index=False
import pandas as pd
df = pd.read_excel("sales.xlsx", parse_dates=["日付"])
df["金額"] = pd.to_numeric(df["金額"], errors="coerce")
monthly = (
df.assign(month=df["日付"].dt.to_period("M"))
.groupby("month", as_index=False)["金額"].sum()
)
by_store = (
df.groupby("店舗", as_index=False)["金額"].sum()
)
with pd.ExcelWriter("sales_report.xlsx") as writer:
monthly.to_excel(writer, sheet_name="月次集計", index=False)
by_store.to_excel(writer, sheet_name="店舗別集計", index=False)
Pythonここでも、すべての to_excel に index=False を付けるのが基本です。
そうすると、どのシートも「余計な左端列なし」で揃います。
あえて index=True にしたいケースは?
インデックス自体に意味があるときだけ
例えば、行ラベルとして「店舗名」や「商品コード」をインデックスにしている場合。
import pandas as pd
df = pd.read_excel("sales_by_store.xlsx", index_col="店舗")
print(df.index) # 店舗名がインデックスになっている
Pythonこの状態で、
df.to_excel("out.xlsx", index=True)
Pythonとすると、左端に「店舗」という列として出力されます。
この場合は、インデックスがそのまま「意味のある列」なので、
index=True でも自然です。
ただし、こういうケースでも、
df = df.reset_index()
df.to_excel("out.xlsx", index=False)
Pythonと書いて、「インデックスを普通の列に戻してから出す」方が、
後から扱いやすいことも多いです。
小さな練習問題
練習1:index あり/なしで Excel 出力を比べてみる
1つ DataFrame を作って、
df.to_excel("with_index.xlsx")
df.to_excel("without_index.xlsx", index=False)
Pythonの2パターンを書き出し、Excel で開いて見比べてみてください。
「どちらを人に渡したいか?」を自分の目で確認すると、感覚がつかめます。
最後に
index=False は、
「Pythonの都合(インデックス)を、Excelの世界に持ち込まない」ための一言です。
これを毎回つけるだけで、
余計な「Unnamed: 0」列が消える
人に渡せるきれいな表になる
後続の処理(別ツールでの読み込みなど)もスムーズになる
という、地味だけど大きな差が生まれます。
これから to_excel を書くときは、
手が勝手に index=False まで打つくらいを“標準フォーム”にしてしまっていいです。
