0Pricing
Pandas & NumPy Academy · レッスン

DataFrameのブールインデックス

列にブール条件を適用して行をフィルタリングし、&と|演算子で複数の条件を組み合わせます。

「DataFrameのブールインデックス」はCoddyKit上の無料Pandas & NumPy Academyレッスンです。 これはレッスン1/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはPandas & NumPy Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Pandas & NumPy Academyコースには全4レッスンが含まれています。

ブールインデックスとは

ブールインデックスを使うと、TrueとFalseの値を持つSeriesを生成する条件を適用して、DataFrameの行をフィルタリングできます。条件がTrueになる行だけが返されます。これは、読みやすく高速であるため、Pandasで最も頻繁に使われる選択方法の1つです。

たとえば、売上DataFrameがある場合、ループを書かずに、売上が1000を超えるすべての行をすぐに取得できます。

import pandas as pd

df = pd.DataFrame({
    'product': ['A', 'B', 'C', 'D'],
    'revenue': [500, 1500, 800, 2000]
})

# Boolean condition produces a Series of True/False
mask = df['revenue'] > 1000
print(mask)
# 0    False
# 1     True
# 2    False
# 3     True

ブールマスクを適用する

ブールマスクを作成したら、それをDataFrameの角括弧内に渡して、一致する行だけを選択します。結果は新しいDataFrameとなり、元のDataFrameが変更されることはありません。元の行インデックスも保持されるため、各行の出所を常に確認できます。

「マスクを作成してから適用する」というパターンは、Pandasで行をフィルタリングする標準的な書き方です。

import pandas as pd

df = pd.DataFrame({
    'product': ['A', 'B', 'C', 'D'],
    'revenue': [500, 1500, 800, 2000]
})

mask = df['revenue'] > 1000
filtered = df[mask]
print(filtered)
#   product  revenue
# 1       B     1500
# 3       D     2000

マスク変数を使わずにインラインで条件を指定する

ブールSeriesを変数に代入する必要はありません。条件を角括弧内にインラインで直接記述できます。df[df['col'] > value]のような1行の書き方は、コードを簡潔で読みやすく保てるため、データ分析用ノートブックでよく使われます。

マスク変数を使う方法とインラインで記述する方法は、どちらも同じ結果になります。条件が複雑な場合や再利用する場合は変数を使い、単純な一度限りのフィルタリングにはインライン記述を使ってください。

import pandas as pd

df = pd.DataFrame({
    'city': ['NYC', 'LA', 'Chicago', 'Houston'],
    'population': [8_336_817, 3_979_576, 2_693_976, 2_320_268]
})

# Inline boolean filter
large_cities = df[df['population'] > 3_000_000]
print(large_cities)
#   city  population
# 0  NYC   8336817
# 1   LA   3979576

&(AND)で条件を組み合わせる

両方の条件を満たす行を取得するには、&演算子で条件を組み合わせます。配列に対して要素単位で動作しないPythonのandキーワードは使わないでください。&は比較演算子より優先順位が高いため、各条件を必ず括弧で囲みます。

結果には、すべてのサブ条件がTrueと評価された行だけが残ります。

import pandas as pd

df = pd.DataFrame({
    'name': ['Alice', 'Bob', 'Carol', 'Dave'],
    'age': [25, 35, 28, 45],
    'salary': [50000, 90000, 70000, 120000]
})

# Both conditions must be true
result = df[(df['age'] > 27) & (df['salary'] > 60000)]
print(result)
#     name  age  salary
# 1    Bob   35   90000
# 2  Carol   28   70000

~で条件を否定する

少なくとも1つの条件が真になる行を残すには、|演算子を使います。&の場合と同様に、各サブ条件を括弧で囲む必要があります。|演算子は、ブール配列に対して要素単位の論理ORを実行します。

&と|を組み合わせて使うことも問題ありません。ただし、正しい評価順を確保し、微妙なロジックのバグを避けるため、括弧の付け方には注意してください。

import pandas as pd

df = pd.DataFrame({
    'product': ['Laptop', 'Mouse', 'Monitor', 'Keyboard'],
    'price': [1200, 25, 300, 80],
    'category': ['Electronics', 'Accessories', 'Electronics', 'Accessories']
})

# Rows where price > 200 OR category is Accessories
result = df[(df['price'] > 200) | (df['category'] == 'Accessories')]
print(result)
#     product  price     category
# 0    Laptop   1200  Electronics
# 1     Mouse     25  Accessories
# 2   Monitor    300  Electronics
# 3  Keyboard     80  Accessories

条件を ~ で否定する

チルダ~演算子はブールSeriesを反転します。つまり、TrueをFalseに、FalseをTrueに変換します。~を使うと「NOT」の論理を表現でき、条件に一致しない行を残せます。反対の条件を手動で組み立てるよりも簡潔です。

たとえば、df[~df['status'].isin(['cancelled', 'refunded'])]は、これら2つのステータス以外のすべての行を残します。

import pandas as pd

df = pd.DataFrame({
    'order_id': [1, 2, 3, 4],
    'status': ['shipped', 'cancelled', 'delivered', 'refunded']
})

# Keep only rows that are NOT cancelled
active = df[~(df['status'] == 'cancelled')]
print(active)
#    order_id     status
# 0         1    shipped
# 2         3  delivered
# 3         4   refunded

文字列値でフィルタリングする

ブールインデックスはテキスト列にも同じように使えます。==で完全一致を検索したり、条件内で.strメソッド(.str.startswith()、.str.contains()、.str.upper()など)を使って柔軟にテキストをフィルタリングしたりできます。

Pandasの文字列比較では、デフォルトで大文字と小文字が区別されます。そのため、'NYC'と'nyc'は異なる値として扱われます。必要に応じて、先に大文字・小文字を統一してください。

import pandas as pd

df = pd.DataFrame({
    'country': ['USA', 'Germany', 'UK', 'USA', 'France'],
    'sales': [400, 200, 150, 600, 300]
})

# Filter rows where country equals USA
us_sales = df[df['country'] == 'USA']
print(us_sales)
#   country  sales
# 0     USA    400
# 3     USA    600

# Filter rows where country starts with 'G'
g_countries = df[df['country'].str.startswith('G')]
print(g_countries)
#    country  sales
# 1  Germany    200

複数の列でフィルタリングする

複雑な分析では、&や|を使って複数の列にまたがる条件を組み合わせることがよくあります。非常に長い条件は、可読性を高めるため、名前付きのブールSeriesに分割してください。それぞれを名前付きのサブフィルターとして作成し、最後に組み合わせます。

この方法では意図が明確になります。各行が、フィルターロジックの一部を説明する日本語の文のように読めるためです。

import pandas as pd

df = pd.DataFrame({
    'region': ['North', 'South', 'North', 'East'],
    'year': [2022, 2023, 2023, 2022],
    'profit': [5000, -200, 8000, 3000]
})

is_north = df['region'] == 'North'
is_2023 = df['year'] == 2023
is_profitable = df['profit'] > 0

result = df[is_north & is_2023 & is_profitable]
print(result)
#   region  year  profit
# 2  North  2023    8000

条件付き列にnp.whereを使う

ブールインデックスは行をフィルタリングしますが、行を削除するのではなく、条件に基づいて新しい列を追加したい場合もあります。np.where(condition, value_if_true, value_if_false)は、列の各要素にif/elseを適用するベクトル化された方法であり、lambdaを使ったapplyよりもはるかに高速です。

import pandas as pd
import numpy as np

df = pd.DataFrame({
    'score': [45, 72, 88, 61, 95]
})

# Create a new column based on a condition
df['grade'] = np.where(df['score'] >= 70, 'Pass', 'Fail')
print(df)
#    score grade
# 0     45  Fail
# 1     72  Pass
# 2     88  Pass
# 3     61  Fail
# 4     95  Pass

フィルタリングした部分集合に値を代入する

.loc[mask, column]を使うと、フィルタリングした行の値をその場で更新できます。これは部分集合に値を設定する安全な方法です。df[mask]['col'] = valueのような連鎖インデックスは、コピーに対して操作するため、SettingWithCopyWarningが発生することがあります。

元のDataFrameをその場で変更したい場合は、必ずdf.loc[mask, 'col'] = valueを優先してください。

import pandas as pd

df = pd.DataFrame({
    'item': ['A', 'B', 'C', 'D'],
    'stock': [0, 5, 0, 12]
})

# Mark out-of-stock items
df.loc[df['stock'] == 0, 'status'] = 'Out of Stock'
df.loc[df['stock'] > 0, 'status'] = 'Available'
print(df)
#   item  stock        status
# 0    A      0  Out of Stock
# 1    B      5     Available
# 2    C      0  Out of Stock
# 3    D     12     Available

マスクを数えたり合計したりする

ブール値は内部的には1(True)と0(False)として扱われるため、マスクに対して.sum()を呼び出すと一致する行数を数えられます。また、.mean()を使うと一致する行の割合を取得できます。こうした簡単な集計により、行を選択する前にフィルターロジックが正しいか確認できます。

import pandas as pd

df = pd.DataFrame({'value': [10, 55, 30, 80, 20, 70]})

mask = df['value'] > 40
print('Count of rows > 40:', mask.sum())      # 3
print('Fraction > 40:', mask.mean().round(2)) # 0.5

# Now apply
print(df[mask])
#    value
# 1     55
# 3     80
# 5     70

クイックチェック

DataFrameのブールインデックスについて理解度を確認しましょう。

レッスンのまとめ

このレッスンでは、次のことを学びました。ブールマスクは、列に条件を適用して行をフィルタリングします。&演算子と|演算子は複数の条件を組み合わせます(Pythonのand/orではありません)。また、~はNOTの論理としてブールマスクを反転します。フィルタリングした行に安全に値を代入するには、df.loc[mask, col] = valueを使ってください。次は、読みやすい文字列としてフィルターを記述できるquery()メソッドを学びます。

よくある質問

「DataFrameのブールインデックス」レッスンは無料ですか?

はい。「DataFrameのブールインデックス」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Pandas & NumPy Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Pandas & NumPy Academyコースには全4レッスンが含まれています。

「DataFrameのブールインデックス」で何を学びますか?

列にブール条件を適用して行をフィルタリングし、&と|演算子で複数の条件を組み合わせます。 ブラウザで直接実行するハンズオンコードでPandas & NumPy Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Pandas & NumPy Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのPandas & NumPy Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン1/4です。

「DataFrameのブールインデックス」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このPandas & NumPy Academyレッスンでコードを書いて実行できますか?

はい。すべてのPandas & NumPy Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. DataFrameのブールインデックス
  2. query()メソッド
  3. isin()とbetween()によるフィルタ
  4. パターンによる列の選択
← Pandas & NumPy Academyに戻る