【Pandas】loc・ilocでデータを選択・抽出する

Pandas

こんにちは、かつコーチです。
pandasを学んでいると必ずぶつかる壁が「locilocって何が違うの?」という疑問です。
名前が似ていて紛らわしいこの2つですが、役割の違いを理解すればもう迷わなくなります。

locとilocとは?

locの定義:ラベルで指定する

locとは、行や列のラベル(名前やインデックスの値)を指定してデータを選択するための機能です。

import pandas as pd

df = pd.DataFrame({
    "名前": ["田中", "佐藤", "鈴木"],
    "年齢": [25, 30, 28]
}, index=["a", "b", "c"])

print(df.loc["b"])
名前    佐藤
年齢    30
Name: b, dtype: object

ilocの定義:位置(番号)で指定する

ilocとは、行や列の位置(0から始まる番号)を指定してデータを選択するための機能です。

print(df.iloc[1])
名前    佐藤
年齢    30
Name: b, dtype: object

インデックスが"a", "b", "c"という文字列でも、ilocなら「何番目か」で指定できます。

なぜ2つの方法が用意されているのか

インデックスは数値の連番だけでなく、日付や商品コードなど、意味のある値を使うことがよくあります。
そのため「ラベルで指定したい場面」と「とにかく何行目かで指定したい場面」の両方が必要になり、locilocという2つの仕組みが用意されています。

基本の書き方:loc・ilocの使い方

手順1:行を指定して抽出する

import pandas as pd

df = pd.DataFrame({
    "商品名": ["りんご", "みかん", "ぶどう", "もも"],
    "価格": [150, 100, 300, 250]
})

# locは「ラベル」なので、この場合は0,1,2と同じ見た目でも意味はラベル指定
print(df.loc[1])

# ilocは常に「位置」なので、必ず2番目のデータになる
print(df.iloc[1])

デフォルトのインデックス(連番)を使っている場合、locilocはどちらも同じ結果になりますが、意味合いは異なります。

手順2:行と列を同時に指定する

# 「価格」列の、1行目のみを取得
print(df.loc[1, "価格"])   # 100
print(df.iloc[1, 1])       # 100

loc[行ラベル, 列名]iloc[行番号, 列番号]という形で、行と列を同時に指定できます。

手順3:条件を指定して抽出する(ブールインデックス)

# 価格が200円以上の商品だけを抽出
expensive = df.loc[df["価格"] >= 200]
print(expensive)
   商品名   価格
2  ぶどう  300
3   もも  250

この「条件式をlocの中に書いて絞り込む」書き方はブールインデックスと呼ばれ、実務で最も頻繁に使うパターンの1つです。

つまずきやすい設定・注意点

  • ilocはスライス(範囲指定)で末尾を含まない一方、locはラベル指定の場合、末尾を含みます
print(df.iloc[0:2])  # 0,1行目のみ(2行目は含まない)
print(df.loc[0:2])   # 0,1,2行目すべて(2を含む)

この違いは非常に間違えやすいので、範囲指定をする際は必ずどちらを使っているか意識してください。

よくあるつまずきポイント・エラー対処

SettingWithCopyWarningが出る

❌Before:locを使わずに、抽出したデータへ直接値を代入してしまう

import pandas as pd

df = pd.DataFrame({
    "商品名": ["りんご", "みかん", "ぶどう"],
    "価格": [150, 100, 300]
})

expensive = df[df["価格"] >= 200]
expensive["価格"] = expensive["価格"] * 0.9  # 割引
SettingWithCopyWarning:
A value is trying to be set on a copy of a slice from a DataFrame.

実際にこのコードを書いたとき、エラーではなく警告(Warning)だったので一度は無視してしまいました。
しかし後で確認すると、意図したdf側のデータが更新されておらず、原因を探すのに時間がかかりました。
expensiveが元のdfのコピーなのか、それとも一部を参照しているだけなのかが曖昧なために起こる警告です。

✅After:抽出と同時にlocを使って値を更新する、または.copy()で明示的にコピーする

# 方法1:locで一気に条件抽出+更新をする
df.loc[df["価格"] >= 200, "価格"] = df.loc[df["価格"] >= 200, "価格"] * 0.9

# 方法2:別データとして扱いたい場合はcopy()を使う
expensive = df[df["価格"] >= 200].copy()
expensive["価格"] = expensive["価格"] * 0.9

「抽出したデータをそのまま書き換えたいのか、別データとして扱いたいのか」を意識して、loc.copy()を使い分けることがポイントです。

応用・一歩先の使い方

複数条件を組み合わせる

複数条件を組み合わせる場合は、&(かつ)や|(または)を使い、各条件をカッコで囲みます。

result = df.loc[(df["価格"] >= 100) & (df["価格"] <= 250)]
print(result)

Pythonのandorは使えない点に注意してください。
df["価格"] >= 100 and df["価格"] <= 250と書くと、ValueErrorが発生します。

列だけを指定して全行取得する

行の条件を指定せず、特定の列だけ全行取得したい場合は、行部分に:を指定します。

print(df.loc[:, "商品名"])

まとめ

この記事のポイント

  • locはラベル(名前)で指定、ilocは位置(番号)で指定する
  • loc[行, 列]のように行と列を同時に指定できる
  • 条件抽出(ブールインデックス)にはlocを使うのが基本
  • 抽出したデータを書き換えるときはSettingWithCopyWarningに注意し、.copy()を活用する
  • 複数条件は&|を使い、各条件をカッコで囲む

次に読むべき記事

データの抽出方法が身についたら、次は実務で必ず直面する「欠損値(NaN)の扱い方:dropna・fillnaの使い分け」に進んでみてください。
抽出したデータに欠損値が混ざっているケースは非常に多く、この2つは合わせて理解しておくと安心です。

タグ: Pandas, 初心者向け, 基本操作

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