なぜ「先頭行をスキップする」がこんなに大事なのか
現場のExcelは、いきなり表が始まってくれません。
会社ロゴ、レポートタイトル、出力日、担当者名、空行…そのあとにようやく「本当のデータ」が出てきます。
でも pandas.read_excel は、何も指定しないと「一番上の行をヘッダー(列名)だ」と勝手に解釈します。
その結果、タイトル行が列名になったり、データが1行ずれて入ったりして、後で必ず苦しむことになります。
そこで使うのが skiprows、特に skiprows=range(n) です。
「先頭から n 行は全部いらない。そこから下が本当の表だ」と、はっきり宣言するためのスイッチです。
基本形:skiprows=range(n) の意味をちゃんと理解する
最小コードと挙動
import pandas as pd
df = pd.read_excel(
"report.xlsx",
skiprows=range(3) # 0,1,2行目(1〜3行目)をスキップ
)
print(df.head())
Pythonskiprows=range(3) は、「0行目・1行目・2行目を読み飛ばす」という意味です。
Excelの見た目で言うと、「1〜3行目を無視して、4行目から読み始める」と考えてください。
ここで重要なのは、range(n) が「0 から n-1 まで」を表す、というPythonの基本ルールです。range(5) なら 0〜4 行目(1〜5行目)をスキップします。
header と組み合わせたときのイメージ
例えば、こんな構造のシートを想像してください。
1行目: 「売上レポート 2025年」
2行目: 「出力日: 2025/01/01」
3行目: 空行
4行目: 「日付, 商品名, 数量, 金額」
5行目以降: データ
この場合、「4行目をヘッダー(列名)として使い、5行目からデータ」としたいわけです。
そのときのコードはこうなります。
df = pd.read_excel(
"report.xlsx",
skiprows=range(3), # 1〜3行目を飛ばす
header=0 # 残った先頭行(元の4行目)をヘッダーにする
)
Pythonskiprows で「どこからが表か」を合わせ、header で「その行を列名として使う」と指定する。
この2つの組み合わせが、実務Excelを読むときの超重要ポイントです。
典型パターン別のテンプレート
タイトルと説明行をまとめて飛ばす
よくあるパターンは、「タイトル1行+説明2行+空行1行+表」という構造です。
import pandas as pd
df = pd.read_excel(
"sales.xlsx",
skiprows=range(4), # 1〜4行目を飛ばす
header=0 # 5行目をヘッダーとして使う
)
print(df.head())
print(df.columns)
Pythonこのとき、df.columns を必ず確認してください。
「想定している列名がちゃんと入っているか」「データの1行目が正しく表示されているか」を目で見るのが、トラブルを防ぐ一番の近道です。
ヘッダー行すらなく、全部データとして扱いたい場合
先頭からいきなりデータが並んでいて、列名は自分で付けたい、というパターンもあります。
さらに、その前にゴミ行がある場合はこうします。
import pandas as pd
df = pd.read_excel(
"no_header_report.xlsx",
skiprows=range(2), # 1〜2行目はゴミ
header=None, # ヘッダー行はない
names=["date", "item", "qty", "amount"] # 自分で列名を付ける
)
print(df.head())
Pythonここでは、
skiprows=range(2)で「3行目からが本当のデータ」と宣言header=Noneで「その3行目も含めて全部データ」と宣言names=[...]で「列名はこれを使う」と指定
という三段構えになっています。
「ヘッダーがないのか」「ヘッダーはあるが無視したいのか」で header=None と header=0 を使い分けるのがポイントです。
先頭 n 行だけでなく、途中の行も飛ばしたい場合
skiprows は、range(n) だけでなく、リストでも指定できます。
例えば「1〜3行目と、10行目だけ飛ばしたい」ならこうです。
df = pd.read_excel(
"report.xlsx",
skiprows=[0, 1, 2, 9], # 0〜2行目と9行目をスキップ
header=0
)
Pythonただし、まずは「先頭のゴミをまとめて飛ばす」パターンをしっかり押さえてから、
こういう細かい指定に進む方が理解がスムーズです。
skiprows と一緒にやっておきたい「型の整え方」
日付と数値を同時に整える
先頭行をスキップして表の位置を合わせたら、次は型を整えます。
import pandas as pd
df = pd.read_excel(
"sales.xlsx",
skiprows=range(4),
header=0,
usecols=["日付", "数量", "金額"],
names=["date", "qty", "amount"],
parse_dates=["date"]
)
df["qty"] = pd.to_numeric(df["qty"], errors="coerce")
df["amount"] = pd.to_numeric(df["amount"], errors="coerce")
print(df.head())
print(df.info())
Pythonここでやっていることは、
skiprowsで「表の開始位置」を合わせるheaderとnamesで「列名」を整えるparse_datesとto_numericで「型」を整える
という、読み込みの三本柱です。skiprows はその最初の一歩で、「どこからが表か」を正しく指定できるかどうかが、後のすべてを決めます。
実践テンプレート
テンプレ1:タイトル3行+空行1行+表、という帳票を読む
import pandas as pd
df = pd.read_excel(
"monthly_report.xlsx",
skiprows=range(4), # 1〜4行目を飛ばす
header=0, # 5行目をヘッダーに
usecols=["日付", "商品名", "数量", "金額"],
names=["date", "item", "qty", "amount"],
parse_dates=["date"]
)
df["qty"] = pd.to_numeric(df["qty"], errors="coerce")
df["amount"] = pd.to_numeric(df["amount"], errors="coerce")
monthly = (
df.assign(month=df["date"].dt.to_period("M"))
.groupby("month", as_index=False)["amount"].sum()
)
print(monthly)
Pythonこのテンプレートは、「先頭にゴミがあるけど、表自体はきれい」という帳票にそのまま使えます。skiprows=range(4) の「4」が、あなたのファイルでは何行になるかを確認して、そこだけ変えればOKです。
テンプレ2:先頭2行が説明、3行目からヘッダーなしデータ
import pandas as pd
df = pd.read_excel(
"raw_data.xlsx",
skiprows=range(2), # 1〜2行目を飛ばす
header=None, # ヘッダーなし
usecols=[0, 1, 3], # 0:日付,1:商品,3:金額
names=["date", "item", "amount"],
parse_dates=["date"]
)
df["amount"] = pd.to_numeric(df["amount"], errors="coerce")
print(df.head())
Pythonこのパターンは、「ヘッダーもないし、先頭に説明行もある」という、かなり荒れたExcelに対して有効です。skiprows と header=None と usecols と names を組み合わせることで、「自分の都合のいい形」に持ってきています。
つまずきポイントを先に潰しておく
「何行スキップすればいいか」がわからない
これは、実際にExcelを開いて「表が始まる行番号」を目で確認するのが一番早いです。
例えば「5行目から表が始まる」なら、0〜3行目をスキップしたいので skiprows=range(4) です。
Excelの行番号(1始まり)と、Pythonの行インデックス(0始まり)を頭の中で対応させてください。
1行目 → 0
2行目 → 1
3行目 → 2
…
n行目 → n-1
なので、「n行目から読みたい」なら skiprows=range(n-1) ではなく、range(n-1) ではなく「range(n-1)?」と一瞬迷うのではなく、
「n行目を含めて、それより上を全部飛ばす」なら range(n-1) ではなく range(n-1)…とややこしく感じたら、素直に「飛ばしたい行の0始まりインデックス」を書き出してみるといいです。
実務では、まずは skiprows=3 のように単純な数値で試し、うまくいかなければ range(3) に変える、というステップでも構いません。
(厳密には skiprows=3 と skiprows=range(3) は挙動が少し違うケースもありますが、先頭連続行を飛ばす用途ではほぼ同じと考えて大丈夫です。)
header と組み合わせを間違える
よくあるミスは、「skiprows で飛ばしたあと、header=None にしてしまう」パターンです。
本当は「飛ばしたあとの先頭行をヘッダーにしたい」のに、ヘッダーなしとして扱ってしまうと、列名が全部番号になってしまいます。
「飛ばしたあとの先頭行を列名にしたい」なら header=0。
「飛ばしたあとの先頭行も含めて全部データにしたい」なら header=None。
ここを意識して選び分けてください。
小さな練習問題
練習1:先頭3行がタイトル+説明、4行目がヘッダーの sales.xlsx を正しく読む
条件は次の通りです。
skiprows=range(3)を使って、4行目から読み始める- 4行目をヘッダーとして使う(
header=0) - 「日付」「金額」列だけを
usecolsで読み、dateとamountという列名にする dateを日付型に、amountを数値型に変換する
自分でコードを書いてみて、df.head() と df.info() で確認してみてください。
練習2:先頭2行がゴミ、3行目からヘッダーなしデータの raw.xlsx を整形する
条件は次の通りです。
skiprows=range(2)で3行目から読み始めるheader=Noneとnames=["date", "item", "qty", "amount"]を使うdateを日付型に、qtyとamountを数値型に変換する- 月ごとの
amount合計を計算して表示する
ここまでできると、「先頭にどんなゴミがあっても、自分で表の開始位置を決めて読み込む」という感覚がかなり身についてきます。
最後に
skiprows=range(n) は、単なる「行スキップのオプション」ではなく、
「このExcelのどこからが本当のデータか」を自分で定義するための道具です。
先頭のゴミ行をきちんと飛ばし、ヘッダー位置を合わせてから、usecols・names・parse_dates・dtype で一気に整える——
この流れを体に染み込ませると、どんなクセのあるExcelでも怖くなくなります。
