TLDR; パンダにおける論理演算子はあり&
、|
かつ~
、括弧は(...)
重要です!
Pythonのand
、or
およびnot
論理演算子はスカラーで動作するように設計されています。したがって、パンダはこの機能のベクトル化された(要素ごとの)バージョンを実現するために、もう1つ改善し、ビットごとの演算子をオーバーライドする必要がありました。
だから、pythonで、次の(exp1
およびexp2
boolean型の結果を評価する式です)...
exp1 and exp2 # Logical AND
exp1 or exp2 # Logical OR
not exp1 # Logical NOT
...に変換されます...
exp1 & exp2 # Element-wise logical AND
exp1 | exp2 # Element-wise logical OR
~exp1 # Element-wise logical NOT
パンダのために。
論理演算を実行しているときにを取得する場合は、ValueError
グループ化に括弧を使用する必要があります。
(exp1) op (exp2)
例えば、
(df['col1'] == x) & (df['col2'] == y)
等々。
ブールインデックス:一般的な操作は、論理条件を介してブールマスクを計算し、データをフィルター処理することです。Pandasには、論理AND、論理OR、論理NOTの 3つの演算子があります。&
|
~
次の設定を検討してください。
np.random.seed(0)
df = pd.DataFrame(np.random.choice(10, (5, 3)), columns=list('ABC'))
df
A B C
0 5 0 3
1 3 7 9
2 3 5 2
3 4 7 6
4 8 8 1
論理AND
df
上記の、あなたはA <5及びBは> 5.これは、個別にそれぞれの条件のためのマスクを計算し、それらをAND演算することによって行われたすべての行を返すしたいと言います。
オーバーロードされたビットごとの&
演算子
続行する前に、ドキュメントのこの特定の抜粋に注意してください。
もう1つの一般的な操作は、ブールベクトルを使用してデータをフィルター処理することです。演算子は、for 、|
for or
、&
for です。デフォルトではPythonはas などの式を評価しますが、必要な評価順序はであるため、これらは括弧を使用してグループ化する必要があります。and
~
not
df.A > 2 & df.B < 3
df.A > (2 &
df.B) < 3
(df.A > 2) & (df.B <
3)
したがって、これを念頭に置いて、要素ごとの論理ANDはビット演算子で実装できます&
。
df['A'] < 5
0 False
1 True
2 True
3 True
4 False
Name: A, dtype: bool
df['B'] > 5
0 False
1 True
2 False
3 True
4 True
Name: B, dtype: bool
(df['A'] < 5) & (df['B'] > 5)
0 False
1 True
2 False
3 True
4 False
dtype: bool
そして、その後のフィルタリング手順は簡単です、
df[(df['A'] < 5) & (df['B'] > 5)]
A B C
1 3 7 9
3 4 7 6
かっこは、ビットごとの演算子のデフォルトの優先順位を上書きするために使用されます。ビット演算子は、条件演算子<
およびよりも優先され>
ます。Pythonのドキュメントの演算子の優先順位のセクションを参照してください。
括弧を使用しない場合、式は誤って評価されます。たとえば、誤って次のようなことを試みた場合
df['A'] < 5 & df['B'] > 5
次のように解析されます
df['A'] < (5 & df['B']) > 5
なる、
df['A'] < something_you_dont_want > 5
これは(連鎖演算子の比較に関するPythonのドキュメントを参照)、
(df['A'] < something_you_dont_want) and (something_you_dont_want > 5)
なる、
# Both operands are Series...
something_else_you_dont_want1 and something_else_you_dont_want2
投げる
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
だから、その間違いをしないでください!1
括弧のグループ化
の回避修正は実際には非常に簡単です。ほとんどのオペレーターには、DataFrameに対応するバウンドメソッドがあります。個々のマスクが条件演算子の代わりに関数を使用して構築されている場合、評価順序を指定するために括弧でグループ化する必要がなくなります。
df['A'].lt(5)
0 True
1 True
2 True
3 True
4 False
Name: A, dtype: bool
df['B'].gt(5)
0 False
1 True
2 False
3 True
4 True
Name: B, dtype: bool
df['A'].lt(5) & df['B'].gt(5)
0 False
1 True
2 False
3 True
4 False
dtype: bool
柔軟な比較に関するセクションを参照してください。。要約すると、
╒════╤════════════╤════════════╕
│ │ Operator │ Function │
╞════╪════════════╪════════════╡
│ 0 │ > │ gt │
├────┼────────────┼────────────┤
│ 1 │ >= │ ge │
├────┼────────────┼────────────┤
│ 2 │ < │ lt │
├────┼────────────┼────────────┤
│ 3 │ <= │ le │
├────┼────────────┼────────────┤
│ 4 │ == │ eq │
├────┼────────────┼────────────┤
│ 5 │ != │ ne │
╘════╧════════════╧════════════╛
括弧を回避するための別のオプションは、DataFrame.query
(またはeval
)の使用です。
df.query('A < 5 and B > 5')
A B C
1 3 7 9
3 4 7 6
私は広範囲に文書化query
しeval
、pd.eval()を使用してパンダで動的式評価を行いました。
operator.and_
この操作を機能的に実行できます。内部的にはSeries.__and__
、ビット演算子に対応する呼び出し。
import operator
operator.and_(df['A'] < 5, df['B'] > 5)
# Same as,
# (df['A'] < 5).__and__(df['B'] > 5)
0 False
1 True
2 False
3 True
4 False
dtype: bool
df[operator.and_(df['A'] < 5, df['B'] > 5)]
A B C
1 3 7 9
3 4 7 6
通常は必要ありませんが、知っておくと便利です。
一般化:(np.logical_and
およびlogical_and.reduce
)
別の代替方法はを使用すること np.logical_and
であり、括弧のグループ化も必要ありません。
np.logical_and(df['A'] < 5, df['B'] > 5)
0 False
1 True
2 False
3 True
4 False
Name: A, dtype: bool
df[np.logical_and(df['A'] < 5, df['B'] > 5)]
A B C
1 3 7 9
3 4 7 6
np.logical_and
はufunc(Universal Functions)であり、ほとんどのufuncにはreduce
メソッドがあります。これはlogical_and
、ANDするマスクが複数ある場合に一般化するのが簡単であることを意味します。たとえば、ANDマスクm1
とm2
and m3
を使用するには&
、次のようにする必要があります。
m1 & m2 & m3
ただし、より簡単なオプションは
np.logical_and.reduce([m1, m2, m3])
これは、より複雑なロジックを使用してこれに基づいて構築できるため、強力です(たとえば、リスト内包で動的にマスクを生成し、それらすべてを追加します)。
import operator
cols = ['A', 'B']
ops = [np.less, np.greater]
values = [5, 5]
m = np.logical_and.reduce([op(df[c], v) for op, c, v in zip(ops, cols, values)])
m
# array([False, True, False, True, False])
df[m]
A B C
1 3 7 9
3 4 7 6
1-私はこの点について不快な思いをしていることを知っていますが、ご容赦ください。これは非常に、非常に一般的な初心者のミス、そして非常に徹底的に説明しなければなりません。
論理OR
df
上記の、あなたはA == 3またはB == 7すべての行を返すしたいと言います。
オーバーロードされたビットごと |
df['A'] == 3
0 False
1 True
2 True
3 False
4 False
Name: A, dtype: bool
df['B'] == 7
0 False
1 True
2 False
3 True
4 False
Name: B, dtype: bool
(df['A'] == 3) | (df['B'] == 7)
0 False
1 True
2 True
3 True
4 False
dtype: bool
df[(df['A'] == 3) | (df['B'] == 7)]
A B C
1 3 7 9
2 3 5 2
3 4 7 6
まだの場合は、上記の論理ANDのセクションもお読みください。すべての注意事項がここに適用されます。
または、この操作は、
df[df['A'].eq(3) | df['B'].eq(7)]
A B C
1 3 7 9
2 3 5 2
3 4 7 6
operator.or_
内部Series.__or__
での呼び出し。
operator.or_(df['A'] == 3, df['B'] == 7)
# Same as,
# (df['A'] == 3).__or__(df['B'] == 7)
0 False
1 True
2 True
3 True
4 False
dtype: bool
df[operator.or_(df['A'] == 3, df['B'] == 7)]
A B C
1 3 7 9
2 3 5 2
3 4 7 6
np.logical_or
2つの条件の場合logical_or
:
np.logical_or(df['A'] == 3, df['B'] == 7)
0 False
1 True
2 True
3 True
4 False
Name: A, dtype: bool
df[np.logical_or(df['A'] == 3, df['B'] == 7)]
A B C
1 3 7 9
2 3 5 2
3 4 7 6
複数のマスクの場合は、次を使用しますlogical_or.reduce
。
np.logical_or.reduce([df['A'] == 3, df['B'] == 7])
# array([False, True, True, True, False])
df[np.logical_or.reduce([df['A'] == 3, df['B'] == 7])]
A B C
1 3 7 9
2 3 5 2
3 4 7 6
論理否定
以下のようなマスクが与えられたとします
mask = pd.Series([True, True, False])
最終結果がになるようにすべてのブール値を反転する必要がある場合[False, False, True]
は、以下のいずれかの方法を使用できます。
ビットごと ~
~mask
0 False
1 False
2 True
dtype: bool
繰り返しになりますが、式は括弧で囲む必要があります。
~(df['A'] == 3)
0 True
1 False
2 False
3 True
4 True
Name: A, dtype: bool
これは内部的に呼び出す
mask.__invert__()
0 False
1 False
2 True
dtype: bool
ただし、直接使用しないでください。
operator.inv
内部的に__invert__
シリーズを呼び出す。
operator.inv(mask)
0 False
1 False
2 True
dtype: bool
np.logical_not
これは派手なバリアントです。
np.logical_not(mask)
0 False
1 False
2 True
dtype: bool
注意は、np.logical_and
の代わりに使用することができるnp.bitwise_and
、logical_or
とbitwise_or
、とlogical_not
とinvert
。