Pythonで複数ヘッダー行のExcelを読み込む入門 — header=[0,1](MultiIndex)
複数行にまたがる見出し(上段が大分類、下段が小分類)の表は、pandas.read_excel の header=[...] でまとめて列名として読み込み、列の階層(MultiIndex)にできます。初心者向けに、動くコード・整形テンプレート・つまずき対策をわかりやすくまとめました。
基本の使い方
import pandas as pd
# 1行目と2行目をヘッダーに使って読み込み(0始まりで [0, 1])
df = pd.read_excel("multi_header.xlsx", header=[0, 1])
print(df.head())
print(df.columns) # ← MultiIndex(階層化された列名)
Python- 効果: 列名が階層化された MultiIndex になります(例:(“売上”, “1月”), (“売上”, “2月”), (“数量”, “1月”) など)。
- 前提: 指定した行に「列名」がきちんと並んでいること。余分なタイトル行がある場合は後述の
skiprowsを併用します。
よくあるレイアウト別テンプレート
タイトルや注記を飛ばしてから複数ヘッダーを取る
import pandas as pd
df = pd.read_excel(
"report.xlsx",
skiprows=3, # 4行目から見出しが始まる
header=[0, 1] # 4行目・5行目がヘッダー
)
Python- 狙い: 帳票の先頭に会社ロゴや説明文がある場合に対応。
3段階のヘッダー(例:カテゴリ / 指標 / 月)
import pandas as pd
df = pd.read_excel("three_levels.xlsx", header=[0, 1, 2])
Python- 狙い: より複雑な多段見出しでも、その段数ぶんを配列で指定すればOK。
必要列だけ読む(usecols)+複数ヘッダー
import pandas as pd
df = pd.read_excel(
"sales.xlsx",
header=[0, 1],
usecols="A:F" # 表の列範囲に合わせて絞る
)
Python- 狙い: 巨大帳票では列を絞ってメモリと速度を確保。
読み込み後の扱い方(選択・集計・フラット化)
階層列の一部だけ選ぶ(タプルで指定)
# 例:上段 "売上" の配下だけ取り出す
sales = df["売上"] # サブDataFrame(列の第2階層が残る)
print(sales.head())
# 例:("売上","1月") 列だけ
jan_sales = df[("売上", "1月")]
Python列名をフラット化(結合して1階層に)
# 欠損ヘッダーは空文字で埋めてから連結
df.columns = ["_".join([str(x) for x in tup if x is not None and str(x) != "nan"]).strip()
for tup in df.columns]
print(df.columns) # 例:["売上_1月", "売上_2月", "数量_1月", ...]
Python- ポイント: フラット化しておくと、後続の加工・保存(CSVなど)がシンプルになります。
列名の正規化(空白除去・日本語→英語)
# 階層の各要素に処理を当てる
df.columns = pd.MultiIndex.from_tuples(
[tuple(str(s).strip() if s is not None else "" for s in tup) for tup in df.columns]
)
Python月次合計などの軽い集計
# MultiIndexのままでも選択して合計可能
total = df["売上"].sum(axis=0) # 各月の合計(横合計)
print(total)
Python実践テンプレート(よくある帳票に合わせる)
テンプレ1:顧客列+売上/数量の多段ヘッダーを読み、売上だけ抽出してCSV化
import pandas as pd
df = pd.read_excel("customer_sales.xlsx", skiprows=2, header=[0, 1])
# 顧客基本情報は単一列名(例:["顧客ID","顧客名"])、指標は多段(例:「売上」「数量」×「1月〜12月」)
base_cols = ["顧客ID", "顧客名"]
sales_df = df["売上"] # 多段の「売上」ブロック
out = pd.concat([df[base_cols], sales_df], axis=1)
out.to_csv("sales_only.csv", index=False)
Pythonテンプレ2:フラット化してから型変換・月次ランキング
import pandas as pd
df = pd.read_excel("multi_header.xlsx", header=[0, 1])
# フラット化
df.columns = ["_".join([str(x).strip() for x in tup if x]) for tup in df.columns]
# 金額列を一括数値化(カンマ対応)
for c in df.columns:
if "売上_" in c:
df[c] = pd.to_numeric(df[c].astype(str).str.replace(",", ""), errors="coerce")
# 例:3月の売上上位5件
top5 = df.nlargest(5, "売上_3月")
print(top5[["顧客ID", "顧客名", "売上_3月"]])
Pythonテンプレ3:多段ヘッダーの部分選択→期間合計
import pandas as pd
df = pd.read_excel("sales.xlsx", header=[0, 1])
# "売上" の 1月〜3月だけ選んで合計列を追加
q1 = df["売上"][["1月", "2月", "3月"]].sum(axis=1)
df[("売上", "Q1合計")] = q1 # 新しい階層列として追加
print(df.head())
Pythonつまずきやすいポイントと回避策
- 上段ヘッダーに結合セルがある:
- 対策: 結合セルが適切に展開されず欠損になることがあります。
skiprowsやheader行の位置を調整。必要ならフラット化して欠損は空文字にして扱う。
- 対策: 結合セルが適切に展開されず欠損になることがあります。
- ヘッダー行に空白や全角半角の揺れ:
- 対策: 読み込み後にヘッダー要素へ
strip()を適用して正規化。比較・選択が安定します。
- 対策: 読み込み後にヘッダー要素へ
- 一部列にヘッダーが欠けている(空セル):
- 対策: MultiIndex の要素が
Noneやnanになります。フラット化時に安全に連結して名前を補う(例:空要素は無視)。
- 対策: MultiIndex の要素が
- 同名の組み合わせが重複する:
- 対策: 後処理で列名を一意化(例:重複検出して “_dup” を付与)。または階層選択時に明示的なタプルで指定。
- 保存時に多段ヘッダーが崩れる(CSV保存):
- 対策: 保存前に列をフラット化。Excel保存なら
to_excelでもMultiIndexは保存可能ですが、読み手のツールによっては見づらいことがあります。
- 対策: 保存前に列をフラット化。Excel保存なら
ミニ例題(練習用)
- 例題1: 二段ヘッダーを読み、”売上” ブロックだけ表示
import pandas as pd
df = pd.read_excel("multi.xlsx", header=[0, 1])
print(df["売上"].head())
Python- 例題2: フラット化して「売上_1月」を数値化して合計
import pandas as pd
df = pd.read_excel("multi.xlsx", header=[0, 1])
df.columns = ["_".join([str(x).strip() for x in tup if x]) for tup in df.columns]
df["売上_1月"] = pd.to_numeric(df["売上_1月"].astype(str).str.replace(",", ""), errors="coerce")
print("1月合計:", df["売上_1月"].sum())
Python- 例題3: 3段ヘッダーから一部階層だけ選択
import pandas as pd
df = pd.read_excel("three_levels.xlsx", header=[0, 1, 2])
# 例:("カテゴリA","売上",["1月","2月"]) を選択
subset = df[("カテゴリA", "売上")][["1月", "2月"]]
print(subset.head())
Python