ブールインデックスとは?
ブールインデックス(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の論理演算子 and
や or
はスカラー(単一の値)に対して動作するため、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. loc
と iloc
の違いに注意
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")
ブールインデックスを使う際は、上記の注意点を意識することで、エラーを防ぎつつ、効率的にデータを処理できます。