- 概要(フィルタリングは「欲しい行だけを、短く正確に抜く」ための基本)
- 基本のブールインデックス(単一条件・複数条件・安全な書き方)
- 行・列を同時に扱うloc/iloc(明確な抽出と可読性)
- 文字列・カテゴリのフィルタ(contains・startswith・カテゴリ化)
- 日時のフィルタ(範囲・月/曜日指定・文字列スライス)
- 範囲・集合・欠損の扱い(between・isin・isna)
- queryの使いどころ(SQL風に読みやすく)
- 条件付き代入とmask/where(抽出だけでなく「置換」も型に)
- グループ・重複・トップNのフィルタ(現場で頻出の型)
- つまずき対策の深掘り(演算子、NaN、dtype、性能)
- 例題(現場でそのまま使えるフィルタの型)
- まとめ(「ブールインデックス」「&|と括弧」「型を整える」。文字列・日時・集合メソッドを使い分ける)
概要(フィルタリングは「欲しい行だけを、短く正確に抜く」ための基本)
pandasのフィルタリングは、条件式でTrue/Falseのマスクを作り、Trueの行だけを抽出するのが基本形です。重要なのは「ブールインデックス」「複数条件の結合(&と|と括弧)」「文字列・日時・範囲・集合の専用メソッド」、そして「欠損の扱い」。これらを型として覚えると、実務の抽出が一気に短く正確になります。
基本のブールインデックス(単一条件・複数条件・安全な書き方)
最小例(単一条件で行を抜く)
import pandas as pd
df = pd.DataFrame({
"name": ["A","B","C","D"],
"age": [25, 30, 22, 28],
"score":[85, 90, 78, 88]
})
adults = df[df["age"] >= 25]
print(adults)
Python列に対する条件式(>=、==、!=、<、>)でTrue/FalseのSeriesを作り、Trueの行のみ残します。
複数条件の結合(& と | と括弧が必須)
cond = (df["age"] >= 25) & (df["score"] >= 85)
selected = df[cond]
print(selected)
Pythonand/orは使えません。&(かつ)、|(または)を使い、各条件を必ず括弧で囲みます。括弧がないと演算子の優先順位で意図が崩れます。
行・列を同時に扱うloc/iloc(明確な抽出と可読性)
行は条件、列は名前で同時指定(loc)
subset = df.loc[df["age"] >= 25, ["name","score"]]
print(subset)
Pythonlocは「行の条件、列名の配列」を同時に指定できます。列を減らして見やすくするのが定石です。
位置ベースで抽出(iloc)
head_two = df.iloc[:2, :] # 先頭2行
middle_col = df.iloc[:, 1] # 2列目(0始まり)
Pythonデータの位置で切るならiloc。列名が未整備でも安全です。
文字列・カテゴリのフィルタ(contains・startswith・カテゴリ化)
部分一致や前方一致で抽出
s = pd.Series(["tokyo", "osaka", "kyoto", "toyama"])
has_to = s[s.str.contains("to", na=False)]
starts_t = s[s.str.startswith("to", na=False)]
Pythonstrアクセサは正規表現にも対応します。na=Falseで欠損時の誤爆を回避。
複数値の集合で抽出(isin)
df2 = pd.DataFrame({"store": ["A","B","C","A","B"], "sales": [100,120,90,110,130]})
picked = df2[df2["store"].isin(["A","C"])]
Python「この集合に属するか」を一発で書けます。否定は~(ビット否定)を使います。
カテゴリ型で順序や性能を改善
cat = pd.CategoricalDtype(categories=["Low","Medium","High"], ordered=True)
df3 = pd.DataFrame({"level": ["High","Low","Medium","Low"]})
df3["level"] = df3["level"].astype(cat)
high_or_more = df3[df3["level"] >= "Medium"]
Python順序ありカテゴリにすると、比較演算が安全・高速になります。
日時のフィルタ(範囲・月/曜日指定・文字列スライス)
範囲抽出の基本(to_datetime→昇順→範囲)
df = pd.DataFrame({
"date": pd.to_datetime(["2025-01-01","2025-01-02","2025-01-10","2025-02-01"]),
"sales":[100,120,80,200]
}).set_index("date").sort_index()
jan = df.loc["2025-01"] # 月指定(文字列スライス)
range_df = df.loc["2025-01-02":"2025-01-10"] # 端点含む範囲
PythonDateTimeIndexなら文字列だけで自然な範囲抽出ができます。必ず日時化して並べ替えてから。
曜日・月で抽出
df = df.reset_index()
weekday = df[df["date"].dt.day_name() == "Wednesday"]
january = df[df["date"].dt.month == 1]
Pythondtアクセサで、曜日・月・時刻の属性を使った条件が書けます。
範囲・集合・欠損の扱い(between・isin・isna)
betweenで閉区間抽出(可読性が高い)
mid = df2[df2["sales"].between(100, 120, inclusive="both")]
Python「A以上B以下」をわかりやすく書けます。
欠損の抽出・否定(isna・notna)
na_rows = df[df["score"].isna()]
valid = df[df["score"].notna()]
Python補完の対象や除外対象を素早く切り分けます。
queryの使いどころ(SQL風に読みやすく)
日本語列名でもスッキリ書ける
df = pd.DataFrame({"年齢":[25,30,22,28], "得点":[85,90,78,88]})
out = df.query("年齢 >= 25 and 得点 >= 85")
Python複雑な条件はqueryが読みやすいことがあります。外部変数は@varで参照できます。
条件付き代入とmask/where(抽出だけでなく「置換」も型に)
whereで条件置換(Falseを値で埋める)
df["score_clean"] = df["score"].where(df["score"] >= 80, 0) # 80未満を0に
Python抽出せずに“列を整形”したいときに強力です。
maskで逆(Trueを値で置換)
df["score_masked"] = df["score"].mask(df["score"] >= 90, 90) # 90以上を90へキャップ
Python上限・下限のキャッピングなどに使えます。
グループ・重複・トップNのフィルタ(現場で頻出の型)
グループ条件でフィルタ(filter)
g = df2.groupby("store")
# 店別で平均売上が110以上のグループだけ残す
kept = g.filter(lambda d: d["sales"].mean() >= 110)
Python「グループ単位で条件を満たす行だけ」を残すときはfilterを使います。
重複を落とす・重複の抽出(duplicated)
unique = df.drop_duplicates(subset=["name"])
dups = df[df.duplicated(subset=["name"], keep=False)]
Pythonキー重複の管理は前処理の基本です。
トップN行の抽出(nlargest/nsmallest)
top3 = df.nlargest(3, "score")
bottom2 = df.nsmallest(2, "score")
Pythonランキング系はsort_valuesより短く書けます。
つまずき対策の深掘り(演算子、NaN、dtype、性能)
& と | と括弧を必ず使う
Pythonのand/orは使えません。各条件を括弧で囲い、&(かつ)・|(または)で結合します。否定は~(ビット否定)です。
NaNは比較で落ちる(必ずisna/notnaを使う)
NaNとの比較はFalseになります。欠損を含む条件はisna/notnaで明示し、誤抽出を防ぎます。
dtypeを先に整える(文字列数値はto_numeric)
型がobjectのままだと数値比較が崩れます。to_numeric(errors=”coerce”)で数値化→NaN化→フィルタが安全です。
大規模データはベクトル化を徹底
applyやループではなく、ブールインデックス・isin・between・str.contains・dt属性・queryを使うと高速です。必要な列だけ選んでから条件を作るのも有効です。
例題(現場でそのまま使えるフィルタの型)
複合条件で安全に抽出(年齢×得点)
cond = (df["age"].between(25, 30)) & (df["score"] >= 85)
out = df.loc[cond, ["name","age","score"]]
print(out)
Python文字列と集合の組み合わせ(店舗A/C、名前が“to”を含む)
store_pick = df2["store"].isin(["A","C"])
name_pick = s.str.contains("to", na=False)
# ブール配列は別DataFrame/Seriesでも同じ長さなら使える
Python日付で月次範囲+曜日抽出
log = pd.DataFrame({
"dt": pd.to_datetime(["2025-01-01","2025-01-02","2025-01-08","2025-02-01"]),
"val":[10,20,15,30]
}).set_index("dt").sort_index()
jan_wed = log.loc["2025-01"][log.loc["2025-01"].index.day_name() == "Wednesday"]
print(jan_wed)
Pythonまとめ(「ブールインデックス」「&|と括弧」「型を整える」。文字列・日時・集合メソッドを使い分ける)
フィルタリングは、ブールインデックスで行を選び、複数条件は&|で結合、各条件は括弧で安全に書くのが基本です。文字列はstr.contains/startswith、集合はisin、範囲はbetween、日時はDateTimeIndexやdt属性で自然に切る。NaNはisna/notnaで明示し、dtypeを整えてから比較する。locで列も同時に絞って可読性を上げ、必要ならquery・where・filterを併用する。この型を身につければ、初心者でも“短く、意図通り、速い”抽出が安定して書けます。
