Pandas의 부울 색인 생성을위한 논리 연산자


152

팬더에서 부울 인덱스로 작업하고 있습니다. 문제는 진술이 왜 :

a[(a['some_column']==some_number) & (a['some_other_column']==some_other_number)]

반면 잘 작동합니다

a[(a['some_column']==some_number) and (a['some_other_column']==some_other_number)]

오류와 함께 종료 하시겠습니까?

예:

a=pd.DataFrame({'x':[1,1],'y':[10,20]})

In: a[(a['x']==1)&(a['y']==10)]
Out:    x   y
     0  1  10

In: a[(a['x']==1) and (a['y']==10)]
Out: ValueError: The truth value of an array with more than one element is ambiguous.     Use a.any() or a.all()

6
이는 배열 / 시리즈의 모든 요소를 ​​다른 요소와 비교할 때 numpy 배열 및 pandas 시리즈가 논리가 아닌 비트 연산자를 사용하기 때문입니다. 따라서이 상황에서 논리 연산자를 사용하는 것은 의미가 없습니다. 관련 참조 : stackoverflow.com/questions/8632033/…
EdChum

9
파이썬에서 and != &. andPython 의 연산자는 재정의 할 수 없지만 &연산자 ( __and__)는 재정의 할 수 없습니다 . 따라서 &numpy와 pandas에서 사용하도록 선택하십시오 .
Steven Rumbalski

답변:


208

당신이 말할 때

(a['x']==1) and (a['y']==10)

암시 적으로 파이썬 에게 부울 값 으로 변환 (a['x']==1)하고 요청 (a['y']==10)합니다.

NumPy 배열 (길이가 1보다 큼) 및 Series와 같은 Pandas 객체에는 부울 값이 없습니다. 즉,

ValueError: The truth value of an array is ambiguous. Use a.empty, a.any() or a.all().

부울 값으로 사용될 때. True 또는 False 여야 할시기가 명확하지 않기 때문 입니다. 일부 사용자는 Python 목록과 같이 길이가 0이 아닌 경우 True라고 가정 할 수 있습니다. 다른 요소는 모든 요소가 True 인 경우에만 True가되기를 원할 수 있습니다 . 다른 사람은 경우에 진실한 할 수 있습니다 어떤 요소의 해당.

많은 상충되는 기대가 있기 때문에 NumPy와 Pandas의 디자이너는 추측을 거부하고 대신 ValueError를 발생시킵니다.

대신 호출하여 명시해야한다 empty(), all()또는 any()당신이 원하는 어떤 행동을 나타내는 방법.

그러나이 경우 부울 평가를 원하지 않고 요소 별 논리 및 논리 를 원하는 것처럼 보입니다 . 이것이 &이진 연산자가 수행하는 것입니다.

(a['x']==1) & (a['y']==10)

부울 배열을 반환합니다.


그건 그렇고, alexpmil이 지적했듯이 괄호는 &보다 연산자 우선 순위 가 높으므로 필수 ==입니다. 괄호가 없으면 체인 비교와 동등한 a['x']==1 & a['y']==10것으로 평가됩니다 . 그것은 형식의 표현입니다 . 두 시리즈와 함께 사용 하면 위와 동일하게 트리거 됩니다. 괄호가 필수 인 이유입니다.a['x'] == (1 & a['y']) == 10(a['x'] == (1 & a['y'])) and ((1 & a['y']) == 10)Series and SeriesandValueError


3
NumPy와 배열이 속성을 가지고 할 경우 가 길이 하나입니다. 팬더 개발자 만 (고집스럽게) 추측을 거부 : P
Andy Hayden

4
'&'는 'and'와 같은 모호한 곡선을 나타내지 않습니까? '&'에 관해서는 어떻게됩니까? 갑자기 모든 사용자가 요소별로해야한다고 동의하지만 'and'를 볼 때 기대치는 다양합니까?
Indominus

16
@Indominus : Python 언어 자체에서는 식이 및 x and y의 평가를 트리거 해야 합니다 . 파이썬은 "먼저 평가하고 , 거짓이면 그 값이 반환되고, 그렇지 않으면 평가되고 결과 값이 반환됩니다." 따라서 구문 은 요소 별 논리에 사용할 수 없으며 반환 되거나 반환 될 수 있기 때문에 사용할 수 없습니다. 반대로 트리거 와 메서드는 원하는 것을 반환하도록 정의 할 수 있습니다. bool(x)bool(y)xxyx and yxyx & yx.__and__(y)__and__
unutbu

2
주의 사항 : ==절 주위의 괄호 는 필수 입니다. a['x']==1 & a['y']==10질문에서와 동일한 오류를 반환합니다.
Alex P. Miller

1
"|"는 무엇입니까?
Euler_Salter

62

TLDR; 팬더의 논리 연산자는 &, |~, 괄호는 (...)중요하다!

파이썬이다 and, ornot논리 연산자는 스칼라와 함께 작동하도록 설계되었습니다. 따라서 Pandas는 이 기능의 벡터화 된 (요소 별) 버전 을 달성하기 위해 더 나은 작업을 수행하고 비트 연산자를 재정의해야했습니다 .

파이썬에서 다음 그래서 ( exp1exp2부울 결과로 평가 표현입니다) ...

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에대해 세 가지 연산자를제공합니다.&|~

다음 설정을 고려하십시오.

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위의, 당신은 <5와 B가> 5.이 개별적으로 각 조건에 대한 마스크를 계산하고이를 AND 연산에 의해 수행되는 모든 행을 반환하고 싶습니다 말한다.

오버로드 된 비트 단위 &연산자
계속하기 전에이 특정 문서의 발췌 내용을 확인하십시오.

또 다른 일반적인 작업은 데이터를 필터링하기 위해 부울 벡터를 사용하는 것입니다. 연산자는 |for or, &for and~for not입니다. 이 괄호를 사용하여 그룹화해야 같은 식을 평가합니다 기본 파이썬으로 이후 df.A > 2 & df.B < 3df.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

괄호는 비트 연산자의 기본 우선 순위를 재정의하는 데 사용되며 조건부 연산자 <및 보다 우선 순위가 높은 비트 연산자 >입니다. 파이썬 문서에서 연산자 우선 순위 섹션을 참조하십시오 .

괄호를 사용하지 않으면식이 잘못 평가됩니다. 예를 들어 실수로

df['A'] < 5 & df['B'] > 5

다음과 같이 파싱됩니다.

df['A'] < (5 & df['B']) > 5

어느 것이

df['A'] < something_you_dont_want > 5

( 연쇄 연산자 비교 에 대한 파이썬 문서 참조 )

(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

나는 pd.eval ()을 사용하여 판다 에서 광범위하게 문서화 query하고 동적 표현 평가를했습니다 .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_andufunc (범용 함수) 이며 대부분의 ufunc에는 reduce메소드가 있습니다. 이는 logical_andAND에 여러 마스크가 있는 경우 일반화하기가 더 쉽다는 것을 의미합니다 . 예를 들어, 및 마스크 m1m2m3함께 &, 당신은해야 할 것

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

아직 논리 및 위 섹션을 읽으 십시오. 여기에 모든 경고 사항이 적용됩니다.

또는이 작업을 사용하여 지정할 수 있습니다

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
두 가지 조건의 경우 다음을 사용하십시오 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

논리 NOT

다음과 같은 마스크가 주어집니다.

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
이것은 numpy 변형입니다.

np.logical_not(mask)

0    False
1    False
2     True
dtype: bool

참고, np.logical_and대체 할 수 np.bitwise_and, logical_orbitwise_or,과 logical_not함께 invert.


TLDR의 @ cs95에서 요소 별 부울 OR의 경우 대신을 사용 |하는 것을 권장 합니다. 왜 그런지 물어봐도 될까요? 이 작업을 위해 특별히 설계 되지 않았 습니까? 각 요소 쌍에 대해 비트 단위로 수행해야하는 부담이 더해지는 이유는 무엇입니까? numpy.bitwise_ornumpy.logical_ornumpy.logical_or
flow2k 2016 년

@ flow2k 관련 텍스트를 인용 해 주시겠습니까? 당신이 말하는 것을 찾을 수 없습니다. FWIW 나는 logical_ *가 올바른 기능적 연산자라고 생각합니다.
cs95

@ cs95 나는 대답의 첫 번째 줄을 언급하고 있습니다 : "TLDR; 판다의 논리 연산자는 &, | 및 ~"입니다.
flow2k 2016 년

@ flow2k 문자 그대로 문서에 있습니다 . "또 다른 일반적인 작업은 데이터를 필터링하기 위해 부울 벡터를 사용하는 것입니다. 연산자는 다음과 같습니다.
cs95

@ cs95, 좋아, 방금이 섹션을 읽었 |으며 요소 별 부울 연산에 사용합니다. 그러나 나에게, 그 문서는 더 "튜토리얼"의, 그리고 대조적으로, 나는이 API 참조 가까이 진리의 소스하다고 생각 : numpy.bitwise_ornumpy.logical_or - 나는 무엇인지 이해하기 위해 노력하고있어 그래서 여기에 설명되어 있습니다.
flow2k 2016 년

4

Pandas의 부울 색인 생성을위한 논리 연산자

Python 논리 연산자 ( and, or또는 not)를 on pandas.Series또는 pandas.DataFrames 에서 사용할 수 없음을 인식하는 것이 중요합니다 (유사하게 numpy.array둘 이상의 요소가있는 s 에서는 사용할 수 없음 ). 그것들을 사용할 수없는 이유는 암시 적으로 bool피연산자를 호출 하여 예외를 던지기 때문입니다.이 데이터 구조는 배열의 부울이 모호하다고 결정했기 때문에 예외를 던졌습니다.

>>> import numpy as np
>>> import pandas as pd
>>> arr = np.array([1,2,3])
>>> s = pd.Series([1,2,3])
>>> df = pd.DataFrame([1,2,3])
>>> bool(arr)
ValueError: The truth value of an array with more than one element is ambiguous. Use a.any() or a.all()
>>> bool(s)
ValueError: The truth value of a Series is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().
>>> bool(df)
ValueError: The truth value of a DataFrame is ambiguous. Use a.empty, a.bool(), a.item(), a.any() or a.all().

나는이 더욱 광범위하게 커버했다 받는 내 대답에 "일련의 진리 값은 모호합니다. 사용 a.empty, a.bool (), a.item (), a.any () 또는 a.all ()"Q + A .

NumPys 논리 함수

그러나 NumPy와는 에 사용될 수있는 함수로서 이들 사업자 소자 현명한 운영 당량 제공 numpy.array, pandas.Series, pandas.DataFrame또는 기타 (준거) numpy.array서브 클래스 :

따라서 본질적으로 팬더 DataFrame 이라고 가정 df1하고 사용해야합니다 df2.

np.logical_and(df1, df2)
np.logical_or(df1, df2)
np.logical_not(df1)
np.logical_xor(df1, df2)

부울에 대한 비트 함수 및 비트 연산자

그러나 boolean NumPy 배열, pandas Series 또는 pandas DataFrames가있는 경우 요소 별 비트 함수를 사용할 수도 있습니다 (부울의 경우 논리 함수와 구별 할 수 없거나 최소한 있어야 함).

일반적으로 연산자가 사용됩니다. 그러나 비교 연산자와 결합하면 비트 연산자가 비교 연산자보다 우선 순위가 높기 때문에 비교를 괄호로 묶어야합니다 .

(df1 < 10) | (df2 > 10)  # instead of the wrong df1 < 10 | df2 > 10

당신이 일반적으로 쓰기 때문에 파이썬 논리 연산자는 비교 연산자보다 낮은 precendence을 가지고 있기 때문 자극 할 수있다 a < 10 and b > 10( a그리고 b예를 들어 간단한 정수위한)와 괄호가 필요하지 않습니다.

논리 연산과 비트 연산의 차이점 (부울이 아닌 경우)

비트 및 논리 연산은 부울 NumPy 배열 (및 부울 시리즈 및 데이터 프레임)에 대해서만 동등하다는 점을 강조하는 것이 중요합니다. 부울이 포함되어 있지 않으면 작업마다 다른 결과가 나타납니다. NumPy 배열을 사용하는 예제를 포함 시키지만 결과는 팬더 데이터 구조와 비슷합니다.

>>> import numpy as np
>>> a1 = np.array([0, 0, 1, 1])
>>> a2 = np.array([0, 1, 0, 1])

>>> np.logical_and(a1, a2)
array([False, False, False,  True])
>>> np.bitwise_and(a1, a2)
array([0, 0, 0, 1], dtype=int32)

그리고 NumPy (및 마찬가지로 팬더)는 부울 ( 부울 또는 "마스크"인덱스 배열 ) 및 정수 ( 인덱스 배열 ) 인덱스에 대해 다른 작업을 수행하므로 인덱싱 결과도 다릅니다.

>>> a3 = np.array([1, 2, 3, 4])

>>> a3[np.logical_and(a1, a2)]
array([4])
>>> a3[np.bitwise_and(a1, a2)]
array([1, 1, 1, 2])

요약표

Logical operator | NumPy logical function | NumPy bitwise function | Bitwise operator
-------------------------------------------------------------------------------------
       and       |  np.logical_and        | np.bitwise_and         |        &
-------------------------------------------------------------------------------------
       or        |  np.logical_or         | np.bitwise_or          |        |
-------------------------------------------------------------------------------------
                 |  np.logical_xor        | np.bitwise_xor         |        ^
-------------------------------------------------------------------------------------
       not       |  np.logical_not        | np.invert              |        ~

어디 논리 연산자가 NumPy와 배열이 작동하지 않습니다 , 시리즈 팬더와 팬더 DataFrames. 다른 사람들은 이러한 데이터 구조 (및 일반 파이썬 객체)를 다루고 요소별로 작동합니다. 그러나 boolbool 은이 문맥에서 정수로 해석되므로 (예 : ~Falsereturns -1~Truereturns -2) 일반 Python에서는 비트 단위 반전에주의하십시오 .

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.