【Pandasエラー解決】Invalid Indexing: Only label-based or position-based indexing are supported の原因と、もう迷わないインデックス操作術

Pandasでデータ分析中に、突然「Invalid Indexing: Only label-based or position-based indexing are supported」なんてエラーに遭遇して、思わず「え、なんで!?」って声が出ちゃった経験、ありますよね? 特にデータフレームから特定の行や列を取り出そうとした時に、このエラーでハマりやすいんです。私も現役時代に何度も同じ壁にぶつかってきましたから、あなたの気持ち、痛いほど分かります。

でも、安心してください。結論から言うと、このエラーの主な原因は、Pandasオブジェクトへのインデックスアクセス方法が、ラベルベース(locまたは位置ベース(ilocのどちらでもない不正な形式であることです。解決策はシンプルで、常にdf.loc[]またはdf.iloc[]を使う習慣をつけること。これだけで、ほとんどの問題は解決します。

1. エラーコード Pandas: Invalid Indexing: Only label-based or position-based indexing are supported とは?

このエラーは、その名の通り「不正なインデックス付け」を意味します。具体的には、PandasのDataFrameやSeriesに対して、loc(ラベルベース)iloc(位置ベース)を使わずに、PythonのリストやNumPy配列のインデックス付けのように多次元のアクセスをしようとしたときに発生します。

例えば、Pythonのリストではmy_list[0][1]のように書けますし、NumPy配列ならmy_array[0, 1]と書くのが一般的ですよね。しかし、PandasのDataFrameでは、これらの書き方が直接適用できない場面があるんです。Pandasはデータ分析に特化しているため、より明示的で安全なインデックスアクセス方法を推奨しているわけです。

このエラーの緊急度は?

緊急度:高! このエラーが発生すると、DataFrameからデータを抽出するという、Pandasの根幹をなす操作が停止してしまいます。つまり、データ分析の作業が先に進まなくなります。放置は厳禁。すぐに解決策を適用しましょう。

2. 最速の解決策 3選

このエラーに遭遇した際、真っ先に確認すべきは「どのようにデータフレームにアクセスしようとしているか?」です。以下の3つの方法のいずれかで、あなたのコードは必ず動くようになります。

解決策1: ラベルベースのインデックスアクセスには .loc[] を使う

特定の行ラベル(インデックス名)列ラベル(列名)を使ってデータにアクセスしたい場合は、.loc[]を使います。これは「このラベルのデータが欲しい!」という時に使います。

import pandas as pd

df = pd.DataFrame({
    'Name': ['Alice', 'Bob', 'Charlie'],
    'Age': [25, 30, 35],
    'City': ['Tokyo', 'Osaka', 'Kyoto']
}, index=['A', 'B', 'C']) # インデックスをカスタムラベルに設定

# NG例: これがエラーの原因になります!
# print(df['A', 'Age']) # Invalid Indexing: Only label-based or position-based indexing are supported

# OK例1: 単一の要素にアクセス (行ラベル 'A', 列ラベル 'Age')
print("df.loc['A', 'Age']:", df.loc['A', 'Age'])

# OK例2: 複数行・複数列にアクセス (行ラベル 'A'から'C'まで, 列ラベル 'Age'と'City')
print("\ndf.loc['A':'C', ['Age', 'City']]:\n", df.loc['A':'C', ['Age', 'City']])

# OK例3: 条件でフィルタリングし、特定の列を選択
print("\ndf.loc[df['Age'] > 30, 'Name']:\n", df.loc[df['Age'] > 30, 'Name'])
ポイント:.loc[]は、名前(ラベル)を使って行と列を指定します。行や列の名前が分かっている場合に非常に強力です!

解決策2: 位置ベースのインデックスアクセスには .iloc[] を使う

データフレームの行番号列番号(0から始まる整数)を使ってデータにアクセスしたい場合は、.iloc[]を使います。これは「この位置にあるデータが欲しい!」という時に使います。

import pandas as pd

df = pd.DataFrame({
    'Name': ['Alice', 'Bob', 'Charlie'],
    'Age': [25, 30, 35],
    'City': ['Tokyo', 'Osaka', 'Kyoto']
}, index=['A', 'B', 'C'])

# NG例: これもエラーの原因になります!
# print(df[0, 1]) # Invalid Indexing: Only label-based or position-based indexing are supported

# OK例1: 単一の要素にアクセス (0行目, 1列目)
print("df.iloc[0, 1]:", df.iloc[0, 1])

# OK例2: 複数行・複数列にアクセス (0行目から1行目まで, 1列目と2列目)
print("\ndf.iloc[0:2, [1, 2]]:\n", df.iloc[0:2, [1, 2]])

# OK例3: 特定の行(スライス)とすべての列
print("\ndf.iloc[1:, :]:\n", df.iloc[1:, :]) # 1行目以降のすべての行、すべての列
ポイント:.iloc[]は、位置(インデックス番号)を使って行と列を指定します。PythonのリストやNumPyのインデックス付けと似た感覚で使えます。

解決策3: 複数列を選択する場合は、列名のリストを渡す

DataFrameから複数の列だけを抽出したい場合は、df[['col1', 'col2']]のように、列名のリストを直接渡します。これはlocilocを使わない特殊なケースですが、非常に頻繁に使うため覚えておきましょう。

import pandas as pd

df = pd.DataFrame({
    'Name': ['Alice', 'Bob', 'Charlie'],
    'Age': [25, 30, 35],
    'City': ['Tokyo', 'Osaka', 'Kyoto']
})

# NG例: 一つの列名をリストに入れずに渡すと Series になる
# print(df['Name']) # これはエラーではないが、DataFrameを返さない

# OK例: 複数の列を選択
print("df[['Name', 'City']]:\n", df[['Name', 'City']])

# OK例: 1つの列だけを選択し、結果をDataFrameとして取得したい場合
print("\ndf[['Name']]:\n", df[['Name']])
ここが落とし穴!

  • df['Name']Series を返します。
  • df[['Name']]DataFrame を返します。

同じ列名でも、返り値の型が異なるので注意してくださいね。

3. エラーの根本原因と再発防止策

根本原因: Pandasのインデックス概念とPython/NumPyの混同

このエラーが頻繁に発生する根本的な原因は、Pandasが持つ独特のインデックス概念にあります。PythonのリストやNumPy配列は、通常、整数ベースの「位置」だけで要素にアクセスします。しかし、PandasのDataFrameは、これに加えて「ラベル(名前)」という概念も持っています。

  • ラベルベース: DataFrameのindex属性やcolumns属性に設定されている、人間が読みやすい名前(文字列や日付など)。
  • 位置ベース: 0から始まる整数で表される、物理的な位置。

多くの人がPythonやNumPyの習慣でdf[0, 'column_name']のようにアクセスしようとしてしまいます。しかし、Pandasはこのような多次元アクセスを直接受け付けません。なぜなら、第一引数(この場合は0)が「行のラベル」なのか「行の位置」なのか、そして第二引数(この場合は'column_name')が「列のラベル」なのか「列の位置」なのかが曖昧になってしまうからです。この曖昧さを避けるために、.loc.ilocという専用のアクセサが用意されているのです。

再発防止策: 「Pandasのインデックスはlociloc」を徹底する!

このエラーを二度と起こさないための最も効果的な方法は、シンプルです。

  • ルールを確立する:PandasのDataFrameやSeriesから特定の行・列・要素を取り出すときは、必ず.loc[].iloc[]を使う!」というルールを自分の中に確立してください。
  • 慣れるまで意識する: 初めは意識的に.loc.ilocを使おうとする必要がありますが、繰り返すうちに自然と手に馴染んできます。
  • 具体的なシナリオで使い分ける:
    • 列名や特定のインデックス名でアクセスしたい場合 → .loc[]
    • 行番号や列番号(整数)でアクセスしたい場合 → .iloc[]
    • 特定の条件に合致する行を選びたい場合(ブールインデックス) → .loc[df['col'] > 10] のように、.locと組み合わせるのが最も明確です。
  • 公式ドキュメントを参照する: 迷ったときは、Pandasのインデックス操作に関する公式ドキュメントを読み返しましょう。体系的な知識が再確認できます。

4. まとめ

今回は、Pandasで多くの人がつまずく「Invalid Indexing: Only label-based or position-based indexing are supported」エラーについて解説しました。

このエラーを解決し、再発を防ぐための最も重要なポイントは以下の2点です。

  • ラベルベースのアクセスには .loc[] を使う。
  • 位置ベースのアクセスには .iloc[] を使う。

Pandasのインデックス操作は、はじめは少しとっつきにくいかもしれませんが、.loc.ilocの使い分けをマスターすれば、データフレームを自由自在に操れるようになります。このエラーは、あなたがPandasの深い理解へと一歩踏み出すための良い機会だったと前向きに捉えてください。

これであなたは、Pandasのインデックス操作マスターの一歩を踏み出しました!素晴らしいデータ分析ライフを楽しんでくださいね!

“`