pandasで複数条件を指定する方法|AND(&)・OR(|)・NOT(~)の書き方とandでエラーになる理由
pandasで複数条件を組み合わせて行を抽出するときは、ANDに &、ORに |、NOTに ~ を使い、条件はそれぞれ丸括弧で囲みます。Pythonの and・or・not をそのまま書くとエラーになりますが、df.query() の文字列の中なら and・or・not が使えます。
この記事では、3つの演算子の基本、括弧を忘れたときに起きること、欠損値(NaN)がある列でNOTを使うときの注意、isin()・between()・query()での書き換えまでを、実行結果つきで説明します。コードは pandas 3.0.6(PyPIで2026年9月17日公開、2026年10月14日確認)と Python 3.12.15 で実行しました。演算子の仕様はpandas公式ドキュメントのBoolean indexingによります。
AND・OR・NOTの基本:&・|・~
import pandas as pd
df = pd.DataFrame({
"商品": ["りんご", "バナナ", "みかん", "牛肉", "鶏肉", "キャベツ"],
"分類": ["果物", "果物", "果物", "肉", "肉", None],
"価格": [150, 100, 80, 900, 300, 200],
"在庫": [30, 0, 50, 5, 12, 8],
})
print("AND: 価格が100以上 かつ 在庫が10以上")
print(df[(df["価格"] >= 100) & (df["在庫"] >= 10)])
print("\nOR: 分類が肉 または 在庫が0")
print(df[(df["分類"] == "肉") | (df["在庫"] == 0)])
print("\nNOT: 分類が果物ではない")
print(df[~(df["分類"] == "果物")])
AND: 価格が100以上 かつ 在庫が10以上
商品 分類 価格 在庫
0 りんご 果物 150 30
4 鶏肉 肉 300 12
OR: 分類が肉 または 在庫が0
商品 分類 価格 在庫
1 バナナ 果物 100 0
3 牛肉 肉 900 5
4 鶏肉 肉 300 12
NOT: 分類が果物ではない
商品 分類 価格 在庫
3 牛肉 肉 900 5
4 鶏肉 肉 300 12
5 キャベツ NaN 200 8
| やりたいこと | pandasの書き方 | 意味 |
|---|---|---|
| AND(かつ) | (条件A) & (条件B) |
両方Trueの行だけ |
| OR(または) | (条件A) | (条件B) |
どちらかがTrueの行 |
| NOT(ではない) | ~(条件A) |
Falseの行(条件を反転) |
| XOR(どちらか一方だけ) | (条件A) ^ (条件B) |
片方だけTrueの行 |
条件式はそれぞれ、行ごとにTrue/Falseが並んだSeries(ブールのSeries)になります。& や | はこのSeriesどうしを行ごとに組み合わせ、df[...] はTrueの行だけを返します。
cond = (df["価格"] >= 100) & (df["在庫"] >= 10)
print(cond)
0 True
1 False
2 False
3 False
4 True
5 False
dtype: bool
and・orを使うとエラーになる理由
try:
df[(df["価格"] >= 100) and (df["在庫"] >= 10)]
except ValueError as e:
print("ValueError:", e)
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
Pythonの and・or・not は、値全体を1つのTrue/Falseに変換しようとします。Seriesには「全体としてTrueかどうか」が決められないため、pandasはValueErrorを出します(公式ドキュメントのFAQ)。行ごとに組み合わせたいときは &・|・~ を使ってください。
括弧を忘れると同じエラーになる
try:
df[df["価格"] >= 100 & df["在庫"] >= 10]
except Exception as e:
print(type(e).__name__ + ":", e)
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
& は >= や == より先に計算されます。そのため括弧がないと、上の式は df["価格"] >= (100 & df["在庫"]) >= 10 と解釈され、比較の連鎖の中で暗黙の and が使われてエラーになります。条件は1つずつ必ず丸括弧で囲む、と覚えておけば迷いません。公式ドキュメントでも、括弧でまとめる必要があると説明されています。
NOT(~)と欠損値(NaN)の注意点
「分類が果物ではない行」を取り出すと、分類が空(NaN)のキャベツも結果に入ります。
print(df[df["分類"] != "果物"]) # != は欠損値の行も残す
print()
print(df[~(df["分類"] == "果物")]) # ~(==) も同じ
print()
print(df[(df["分類"] != "果物") & df["分類"].notna()]) # 欠損値を除く
商品 分類 価格 在庫
3 牛肉 肉 900 5
4 鶏肉 肉 300 12
5 キャベツ NaN 200 8
商品 分類 価格 在庫
3 牛肉 肉 900 5
4 鶏肉 肉 300 12
5 キャベツ NaN 200 8
商品 分類 価格 在庫
3 牛肉 肉 900 5
4 鶏肉 肉 300 12
欠損値との == は常にFalseになるので、~ で反転するとTrueになり、NaNの行が残ります。!= も同じ結果です。「果物以外の分類が入っている行」だけがほしいときは、notna() をANDで加えます。
OR条件が多いときは isin()、範囲なら between()
print(df[df["商品"].isin(["りんご", "牛肉", "キャベツ"])])
print()
print(df[~df["商品"].isin(["りんご", "牛肉", "キャベツ"])]) # NOT IN
print()
print(df[df["価格"].between(100, 300)]) # 100以上300以下(両端を含む)
商品 分類 価格 在庫
0 りんご 果物 150 30
3 牛肉 肉 900 5
5 キャベツ NaN 200 8
商品 分類 価格 在庫
1 バナナ 果物 100 0
2 みかん 果物 80 50
4 鶏肉 肉 300 12
商品 分類 価格 在庫
0 りんご 果物 150 30
1 バナナ 果物 100 0
4 鶏肉 肉 300 12
5 キャベツ NaN 200 8
同じ列に対する「AまたはBまたはC」は、isin()にリストを渡すと1行で書けます。~ を付ければ「リストに含まれない(NOT IN)」になります。「100以上300以下」のような範囲は between() が便利で、既定では両端を含みます。
query()なら and・or・not がそのまま書ける
print(df.query("価格 >= 100 and 在庫 >= 10"))
print()
print(df.query("分類 == '肉' or 在庫 == 0"))
print()
print(df.query("not 商品 in ['りんご', '牛肉']"))
print()
limit = 200
print(df.query("価格 <= @limit and 分類 == '果物'"))
商品 分類 価格 在庫
0 りんご 果物 150 30
4 鶏肉 肉 300 12
商品 分類 価格 在庫
1 バナナ 果物 100 0
3 牛肉 肉 900 5
4 鶏肉 肉 300 12
商品 分類 価格 在庫
1 バナナ 果物 100 0
2 みかん 果物 80 50
4 鶏肉 肉 300 12
5 キャベツ NaN 200 8
商品 分類 価格 在庫
0 りんご 果物 150 30
1 バナナ 果物 100 0
2 みかん 果物 80 50
DataFrame.query() の文字列の中では、and・or・not や in を使えます(&・| も可)。Pythonの変数は @limit のように @ を付けて参照します。列名を何度も書かなくてよいので、条件が長くなるときに読みやすくなります。詳しくはPandas DataFrame query()メソッドで条件抽出を簡単にで解説しています。
文字列を含む・含まないで絞る
print(df[df["商品"].str.contains("肉")])
print()
print(df[~df["分類"].str.contains("果", na=False)]) # 欠損値をFalse扱いにしてから反転
商品 分類 価格 在庫
3 牛肉 肉 900 5
4 鶏肉 肉 300 12
商品 分類 価格 在庫
3 牛肉 肉 900 5
4 鶏肉 肉 300 12
5 キャベツ NaN 200 8
部分一致は str.contains() を使います。欠損値がある列で ~ を付けるときは、na=False を指定して欠損値をFalseにしてから反転すると、エラーや意図しない結果を避けられます。上の例では、分類に「果」を含まない行として、肉の2行と分類が空のキャベツが残りました。
条件が多いとき・抽出した行に値を入れるとき
import numpy as np
conds = [df["価格"] >= 100, df["在庫"] > 0, df["分類"].notna()]
print(df[np.logical_and.reduce(conds)])
print()
print(df[(df["価格"] >= 200) ^ (df["在庫"] >= 10)]) # どちらか一方だけ(XOR)
print()
df.loc[(df["在庫"] < 10) & (df["分類"] == "肉"), "発注"] = "要"
print(df)
商品 分類 価格 在庫
0 りんご 果物 150 30
3 牛肉 肉 900 5
4 鶏肉 肉 300 12
商品 分類 価格 在庫
0 りんご 果物 150 30
2 みかん 果物 80 50
3 牛肉 肉 900 5
5 キャベツ NaN 200 8
商品 分類 価格 在庫 発注
0 りんご 果物 150 30 NaN
1 バナナ 果物 100 0 NaN
2 みかん 果物 80 50 NaN
3 牛肉 肉 900 5 要
4 鶏肉 肉 300 12 NaN
5 キャベツ NaN 200 8 NaN
- 条件が3つ以上あるなら、リストにまとめて
np.logical_and.reduce()(ORならnp.logical_or.reduce())で一度に結合できます。 ^は「どちらか一方だけ」を表すXORです。- 条件に合う行の列に値を代入するときは、
df.loc[条件, "列名"] = 値と書きます。df[条件]["列名"] = 値のような連鎖した代入は、pandas 3.0ではもとのDataFrameに反映されず、ChainedAssignmentError という警告が出ます(公式ドキュメントのCopy-on-Write)。
書き方の早見表
| やりたいこと | ブールインデックス | query() |
|---|---|---|
| AかつB | df[(A) & (B)] |
df.query("A and B") |
| AまたはB | df[(A) | (B)] |
df.query("A or B") |
| Aではない | df[~(A)] |
df.query("not A") |
| リストのどれか | df[df["列"].isin(リスト)] |
df.query("列 in @リスト") |
| リストのどれでもない | df[~df["列"].isin(リスト)] |
df.query("列 not in @リスト") |
行の取り出し方全般はpandasの使い方を初心者向けに解説、列名で列を選ぶ方法はPandas filter()の記事も参考にしてください。
よくある質問
Q. pandasでOR条件はどう書きますか?
縦棒 | を使い、条件をそれぞれ丸括弧で囲んで df[(df[“A”] == 1) | (df[“B”] > 10)] のように書きます。同じ列で値の候補が複数あるなら df[df[“A”].isin([1, 2, 3])] のほうが簡潔です。
Q. pandasでNOT条件(〜ではない)はどう書きますか?
チルダ ~ を条件の前に付けて df[~(df[“A”] == 1)] と書きます。リストに含まれない行は df[~df[“A”].isin(リスト)] です。欠損値の行も残る点に注意してください。
Q. andやorを使うと「The truth value of a Series is ambiguous」と出るのはなぜですか?
Pythonの and・or・not はSeries全体を1つのTrue/Falseに変換しようとし、pandasはそれを決められないためValueErrorを出します。行ごとに組み合わせるには &・|・~ を使います。
Q. & を使ったのにエラーになります。
条件を丸括弧で囲んでいない可能性があります。& は比較演算子より先に計算されるため、(df[“A”] > 1) & (df[“B”] < 5) のように条件ごとに括弧が必要です。
Q. query()で and・or は使えますか?
使えます。df.query(“価格 >= 100 and 在庫 >= 10”) のように文字列の中に書きます。not や in も使え、Pythonの変数は @変数名 で参照します。
まとめ
pandasの複数条件は、AND=&、OR=|、NOT=~ で組み合わせ、条件ごとに丸括弧で囲むのが基本です。and・orを使いたいときは query() に切り替え、同じ列の候補が多いときは isin()、範囲なら between() を使うと短く書けます。NOTで反転すると欠損値の行も残ることだけは、結果を見て確かめる習慣をつけておきましょう。
pandas|抽出・選択の関連記事
loc・ilocや条件指定で、必要な行・列だけを取り出す操作の記事です。
- DataFrameとSeriesの先頭・末尾をサッと表示!head()とtail()を使いこなそう
- DataFrame・Seriesの重複データを抽出・削除する方法
- MultiIndexから任意の行・列を自在に選択・抽出する方法
- 特定の条件を満たす要素数をカウントする方法(全体・行・列ごと)
- Pandas DataFrame query()メソッドで条件抽出を簡単に!使い方とサンプルコード集
- Pandas filter()で特定の行・列を効率抽出!名前の条件でデータ選択
pandas全体の使い方は「pandasの使い方を初心者向けに解説」でまとめています。







