Pandasのブールインデックス入門:データを効率的に抽出する方法

ブールインデックスとは?

ブールインデックス(Boolean Indexing)とは、Pandasのデータフレームやシリーズから特定の条件を満たすデータを抽出するための手法です。True または False のブール値を持つリストや配列を使い、それに対応する行や列を選択できます。

ブールインデックスの基本動作

例えば、以下のようなデータフレームがあるとします。

import pandas as pd

# サンプルデータの作成
data = {
    "名前": ["Alice", "Bob", "Charlie", "David"],
    "年齢": [25, 30, 35, 40],
    "得点": [85, 90, 78, 88]
}
df = pd.DataFrame(data)

print(df)

このデータフレームは次のようになります。

      名前  年齢  得点
0  Alice  25  85
1    Bob  30  90
2  Charlie  35  78
3  David  40  88

ここで、年齢30 以上の行だけを抽出するには、ブールインデックスを使用して以下のように記述します。

df[df["年齢"] >= 30]

出力は以下のようになります。

      名前  年齢  得点
1    Bob  30  90
2  Charlie  35  78
3  David  40  88

このように、df["年齢"] >= 30 の結果は True または False の配列となり、それをデータフレームのインデックスとして指定することで、該当する行のみを抽出できます。

Pandasでのブールインデックスの基本

Pandasでブールインデックスを使用する基本的な方法を紹介します。ブールインデックスを活用すると、条件を満たすデータのみを簡単に抽出できます。

1. 単一条件でのフィルタリング

データフレームの特定の列に対して条件を指定し、それに該当する行を取得できます。

import pandas as pd

# サンプルデータの作成
data = {
    "名前": ["Alice", "Bob", "Charlie", "David"],
    "年齢": [25, 30, 35, 40],
    "得点": [85, 90, 78, 88]
}
df = pd.DataFrame(data)

# 年齢が30以上の行を抽出
df_filtered = df[df["年齢"] >= 30]
print(df_filtered)

出力:

      名前  年齢  得点
1    Bob  30  90
2  Charlie  35  78
3  David  40  88

2. 複数条件を組み合わせる

&(AND)や |(OR)を使うことで、複数の条件を組み合わせたフィルタリングが可能です。

AND 条件(両方の条件を満たす)

df_filtered = df[(df["年齢"] >= 30) & (df["得点"] > 80)]
print(df_filtered)

出力:

    名前  年齢  得点
1   Bob  30  90
3  David  40  88

OR 条件(いずれかの条件を満たす)

df_filtered = df[(df["年齢"] >= 30) | (df["得点"] > 80)]
print(df_filtered)

出力:

      名前  年齢  得点
0  Alice  25  85
1    Bob  30  90
2  Charlie  35  78
3  David  40  88

3. isin() を使ったフィルタリング

isin() を使うと、特定の値のリストに含まれるデータを簡単に抽出できます。

df_filtered = df[df["名前"].isin(["Alice", "Charlie"])]
print(df_filtered)

出力:

      名前  年齢  得点
0  Alice  25  85
2  Charlie  35  78

4. ~ を使った否定(NOT 条件)

条件に合致しないデータを取得するには、~(NOT)を使います。

df_filtered = df[~(df["年齢"] >= 30)]
print(df_filtered)

出力:

     名前  年齢  得点
0  Alice  25  85

このように、Pandasのブールインデックスを活用すると、シンプルな記述でデータを柔軟に抽出できます。

複数条件のブールインデックス

Pandasでは、ブールインデックスを用いることで複数の条件を組み合わせたデータ抽出が可能です。&(AND)、|(OR)、~(NOT)などの演算子を使うことで、より高度なフィルタリングが行えます。

1. AND 条件(両方の条件を満たす)

& を使うことで、複数の条件を同時に満たすデータを抽出できます。例えば、「年齢が30歳以上」かつ「得点が80点以上」のデータを取得する場合は以下のように記述します。

import pandas as pd

# サンプルデータの作成
data = {
    "名前": ["Alice", "Bob", "Charlie", "David"],
    "年齢": [25, 30, 35, 40],
    "得点": [85, 90, 78, 88]
}
df = pd.DataFrame(data)

# 年齢が30以上かつ得点が80以上のデータを抽出
df_filtered = df[(df["年齢"] >= 30) & (df["得点"] >= 80)]
print(df_filtered)

出力:

    名前  年齢  得点
1   Bob  30  90
3  David  40  88

2. OR 条件(いずれかの条件を満たす)

| を使うことで、いずれかの条件を満たすデータを取得できます。例えば、「年齢が30歳以上」または「得点が80点以上」のデータを抽出するには、次のように記述します。

df_filtered = df[(df["年齢"] >= 30) | (df["得点"] >= 80)]
print(df_filtered)

出力:

      名前  年齢  得点
0  Alice  25  85
1    Bob  30  90
2  Charlie  35  78
3  David  40  88

3. NOT 条件(特定の条件を除外)

~(チルダ)を使うことで、特定の条件を満たさないデータを取得できます。例えば、「年齢が30歳未満のデータを除外する」場合は以下のように書きます。

df_filtered = df[~(df["年齢"] < 30)]
print(df_filtered)

出力:

      名前  年齢  得点
1    Bob  30  90
2  Charlie  35  78
3  David  40  88

4. isin() を用いた条件指定

isin() を使うことで、特定の値のリストに該当するデータのみを抽出できます。例えば、「名前が Alice または Charlie のデータ」を取得するには次のように記述します。

df_filtered = df[df["名前"].isin(["Alice", "Charlie"])]
print(df_filtered)

出力:

      名前  年齢  得点
0  Alice  25  85
2  Charlie  35  78

5. 複雑な条件の組み合わせ

AND、OR、NOTを組み合わせることで、より細かい条件でデータを抽出できます。例えば、「年齢が30歳以上」かつ「得点が80点以上」、または「名前がAlice」のデータを取得するには次のように書きます。

df_filtered = df[((df["年齢"] >= 30) & (df["得点"] >= 80)) | (df["名前"] == "Alice")]
print(df_filtered)

出力:

      名前  年齢  得点
0  Alice  25  85
1    Bob  30  90
3  David  40  88

このように、Pandasのブールインデックスを使えば、複数の条件を柔軟に組み合わせたデータ抽出が可能です。条件を適切に指定することで、必要なデータのみを効率的に取得できます。

ブールインデックスの応用例

ブールインデックスを活用すると、Pandasのデータ処理をより効率的に行うことができます。ここでは、具体的な応用例を紹介します。

1. 欠損値を含むデータの処理

データには欠損値(NaN)が含まれることがあります。ブールインデックスを使って、欠損値の有無によるフィルタリングが可能です。

import pandas as pd
import numpy as np

# サンプルデータの作成
data = {
    "名前": ["Alice", "Bob", "Charlie", "David"],
    "年齢": [25, np.nan, 35, 40],
    "得点": [85, 90, np.nan, 88]
}
df = pd.DataFrame(data)

# 欠損値を含む行を取得
df_missing = df[df.isnull().any(axis=1)]
print(df_missing)

出力:

      名前  年齢  得点
1    Bob NaN  90.0
2  Charlie 35.0  NaN

また、欠損値を含まない行のみを取得することもできます。

df_clean = df[df.notnull().all(axis=1)]
print(df_clean)

出力:

    名前  年齢  得点
0  Alice  25.0  85.0
3  David  40.0  88.0

2. 特定の範囲のデータを抽出

例えば、得点が80点以上90点以下のデータのみを取得する場合、次のように記述できます。

df_filtered = df[(df["得点"] >= 80) & (df["得点"] <= 90)]
print(df_filtered)

出力:

    名前  年齢  得点
0  Alice  25.0  85.0
1    Bob   NaN  90.0
3  David  40.0  88.0

3. 特定の文字列を含むデータを抽出

str.contains() を使うことで、特定の文字列を含むデータを取得できます。例えば、名前"a" を含む人を抽出するには次のように書きます。

df_filtered = df[df["名前"].str.contains("a", case=False, na=False)]
print(df_filtered)

出力:

      名前  年齢  得点
0  Alice  25.0  85.0
2  Charlie 35.0   NaN
3  David  40.0  88.0

4. ランク付けによる上位・下位データの抽出

得点の上位2名を抽出する場合、nlargest() を使用できます。

df_top2 = df.nlargest(2, "得点")
print(df_top2)

出力:

    名前  年齢  得点
1   Bob   NaN  90.0
3  David  40.0  88.0

逆に、得点の下位2名を取得する場合は nsmallest() を使用します。

df_bottom2 = df.nsmallest(2, "得点")
print(df_bottom2)

出力:

      名前  年齢  得点
2  Charlie 35.0   NaN
0    Alice 25.0  85.0

5. 条件を満たすデータの一括更新

例えば、得点が 80 未満の人の得点を 80 に修正したい場合、ブールインデックスを使って一括変更できます。

df.loc[df["得点"] < 80, "得点"] = 80
print(df)

このように、ブールインデックスはデータの抽出だけでなく、データの更新にも活用できます。


ブールインデックスを応用することで、データのクリーニング、特定条件の抽出、ランキングの取得など、多くの場面で効率的にデータを処理できます。

ブールインデックスを使う際の注意点

Pandasのブールインデックスは便利ですが、適切に使用しないと意図しない結果を招くことがあります。ここでは、ブールインデックスを使う際の注意点を紹介します。

1. &| を使う際の注意点(and / or は使えない)

Pythonの論理演算子 andor はスカラー(単一の値)に対して動作するため、Pandasのシリーズに対して使うとエラーが発生します。

誤った例(エラーになる)

df_filtered = df[(df["年齢"] >= 30) and (df["得点"] > 80)]  # エラー

エラーメッセージ:

ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().

正しい例(&| を使用)

df_filtered = df[(df["年齢"] >= 30) & (df["得点"] > 80)]

また、&| を使う際には、各条件を必ず () で囲む 必要があります。

誤った例(エラーになる可能性がある)

df_filtered = df[df["年齢"] >= 30 & df["得点"] > 80]  # エラー

正しい例

df_filtered = df[(df["年齢"] >= 30) & (df["得点"] > 80)]

2. NaN(欠損値)の扱い

ブールインデックスを適用すると、NaN を含むデータが期待通りにフィルタリングされないことがあります。比較演算 (>=, <=, ==) を行うと、NaN に対する結果は False になります。

例: NaN を含むデータ

import pandas as pd
import numpy as np

data = {
    "名前": ["Alice", "Bob", "Charlie", "David"],
    "年齢": [25, np.nan, 35, 40],
    "得点": [85, 90, np.nan, 88]
}
df = pd.DataFrame(data)

# 年齢が30以上のデータを取得
df_filtered = df[df["年齢"] >= 30]
print(df_filtered)

出力(NaN を含む行が除外される):

      名前  年齢  得点
2  Charlie 35.0   NaN
3  David  40.0  88.0

NaN を考慮して処理する方法

  • fillna() で欠損値を置き換える
  • dropna() で欠損値を含む行を削除する
  • isna()notna() を使って NaN を含む行だけを取得・除外する
df_filtered = df[df["年齢"].notna()]  # 年齢がNaNでないデータのみ取得

3. インデックスがリセットされない

ブールインデックスを適用すると、フィルタされた行のインデックスは元のままになります。

df_filtered = df[df["年齢"] >= 30]
print(df_filtered)

出力(インデックスが元のまま):

      名前  年齢  得点
2  Charlie 35.0   NaN
3  David  40.0  88.0

このままでは、連番のインデックスになっていないため、リセットする場合は reset_index() を使います。

df_filtered = df[df["年齢"] >= 30].reset_index(drop=True)
print(df_filtered)

出力(インデックスがリセットされる):

      名前  年齢  得点
0  Charlie 35.0   NaN
1  David  40.0  88.0

4. lociloc の違いに注意

Pandasの locラベルベースのインデックス指定、iloc位置ベースのインデックス指定を行います。ブールインデックスを使用する場合、通常は loc を使います。

df_filtered = df.loc[df["得点"] > 80]

しかし、誤って iloc を使うとエラーになる可能性があります。

誤った例(エラーになる)

df_filtered = df.iloc[df["得点"] > 80]  # エラー

iloc は整数インデックスが必要なため、ブールインデックスには対応していません。

5. パフォーマンスに注意(特に大規模データ)

ブールインデックスを使うと、フィルタリング処理がシンプルに記述できますが、大量のデータを処理する場合、速度が低下することがあります。

パフォーマンス改善のための方法

  • カテゴリー型 (category) を使用
    文字列データが多い場合、category 型に変換するとメモリ使用量が削減され、処理速度が向上することがあります。 df["名前"] = df["名前"].astype("category")
  • query() を使う
    query() を使うと、ブールインデックスよりも高速に処理できる場合があります。 df_filtered = df.query("年齢 >= 30 and 得点 > 80")

ブールインデックスを使う際は、上記の注意点を意識することで、エラーを防ぎつつ、効率的にデータを処理できます。

投稿者 admin

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です