본문 바로가기
Python/Pandas

query 메서드 옵션, 설명, 사용 예-pandas(18)

by 콩돌 2019. 10. 31.
반응형

파이썬 버전 3.7 기준

pandas 버전 0.25.1 기준



 query 메서드 옵션, 설명, 사용 예


본 포스팅에서는 query 메서드의 대한 내용, 설명, 사용 예 등을 서술한다.


 query 메서드


pandas에서 DataFrame은 query 메서드를 지원한다.

이 메서드는 조건식을 문자열로 입력받아 해당 조건에 만족하는 행을 추출해 출력해주는 함수이다.

사용 방법은 간단한데, 단순히 대괄호[ ]에서 조건식을 입력했던 것과 동일하게 입력을 해주면 되나 차이점은 문자열이 들어간다는 것이다. 


query() 메서드 사용형식)

DataFrame.query(expr, inplace=False)


expr은 입력되는 조건식을 입력받는다.

  ○ 입력되는 조건식은 문자열로 입력받는다.

inplace가 True일 경우 query에 의해 출력된 데이터로 원본 데이터를 대체한다. 


참고사항(query 메서드를 굳이 사용하는 이유?)

  사실 대괄호[ ]를 사용하여 조건식을 입력해도 되는데 굳이 query 메서드를 사용하는 이유는 방대한 양의 데이터를 처리할 경우 이 메서드가 성능면에서 우위를 보여준다.

  ○ pandas 공식 사이트에서는 약 200,000개의 행 이상을 처리할 경우에는 이 메서드가 성능면에서 우위를 보인다고 설명한다.

  ○ 하지만 적은 양의 데이터를 처리할 경우 큰 차이는 보이지 않는다.  


query메서드의 특징

query 메서드의 특징으로는 다음과 같다.

  ○ 표현식을 문자열로 입력받는다.

  ○ 단순하게 열의 레이블을 표현식에 넣어 사용이 가능하다.

  ○ index 역시 표현식에 넣어 사용이 가능하다.

  ○ 대용량의 데이터를 처리할 경우 대괄호 조건식을 사용하는 것 보다 성능이 좋다.

  ○ 비교연산자와 논리연산자 중 비교연산자가 우선순위가 있으므로 표현식이 단순해진다.


query에 적용되는 조건식의 문법 특징

조건식사용은 다음 예제와 같이 적용될 수 있다.

  ○ query메서드와 대괄호[ ]를 사용한 결과는 동일하다.


조건식 사용 예)

DataFrame[ (DataFrame.a < DataFrame.b) & (DataFrame.b < DataFrame.c) ]

DataFrame.query( '(a < b) & (b < c)' )


하지만 비교연산자가 논리연산자보다 우위에 있다는 점을 이용하면 이런 문법을 더욱 단순화 시킬 수 있다.

  ○ 먼저 위 예제에서 소괄호()를 지울 수 있다.

  ○ 논리연산자의 경우 심볼 대신에 영어를 사용할 수도 있다.

  ○ 비교연산자가 논리연산자(&와 |)보다 우선순위가 높다.

아래 예제의 ①, ②, ③은 모두 동등한 결과를 보여준다.


단순문법 사용 예)

① DataFrame.query( 'a < b & b < c' )

② DataFrame.query( 'a < b and b < c' )

③ DataFrame.query( 'a < b < c' )



 query 메서드 단순 사용 예제

다음 예제는 c0열과 c2열 사이에 c1의 값이 존재하는 행만 추출해 출력하는 것을 보여준다.

 

query 메서드 사용 예)

# pandas와 numpy의 import

In[2]: import pandas as pd

In[3]: import numpy as np


# 예제용 배열 선언 

In[4]: ex_df=pd.DataFrame([[0,1,2], [3,4,5], [8,7,9]], index=['r0','r1','r2'], columns=['c0','c1','c2'])


In[5]: ex_df.query('c0<c1<c2')

Out[5]: 

    c0  c1  c2

r0   0   1   2

r1   3   4   5



 index 객체로의 사용 예제

입력된 이름을 가진 열이 없고 인덱스의 이름과 일치할 경우 인덱스 객체로 동일한 작업을 수행한다.


index 객체로의 query 메서드 사용 예 1)

# pandas와 numpy의 import

In[2]: import pandas as pd

In[3]: import numpy as np


# 예제용 배열 선언 및 인덱스 이름 명명

In[6]: ex_df=pd.DataFrame([[0,1,2], [3,4,5], [8,7,9]], columns=['c0','c1','c2'])

In[7]: ex_df.index.name='c_i'

In[8]: ex_df

Out[8]: 

     c0  c1  c2

c_i            

0     0   1   2

1     3   4   5

2     8   7   9


# index 객체에의 조건식 적용

In[9]: ex_df.query('c_i>=1')

Out[9]: 

     c0  c1  c2

c_i            

1     3   4   5

2     8   7   9


인덱스 이름을 지정하지 않은 경우는 query 표현식에 index라는 이름으로 사용할 수 있다.


index 객체로의 query 메서드 사용 예 2)

# pandas와 numpy의 import

In[2]: import pandas as pd

In[3]: import numpy as np


# 예제용 배열 선언 및 인덱스 이름 명명

In[6]: ex_df=pd.DataFrame([[0,1,2], [3,4,5], [8,7,9]], columns=['c0','c1','c2'])

In[7]: ex_df.index.name='c_i'

In[8]: ex_df

Out[8]: 

     c0  c1  c2

c_i            

0     0   1   2

1     3   4   5

2     8   7   9


# index 객체에의 조건식 적용

In[10]: ex_df.query('index>=1')

Out[10]: 

     c0  c1  c2

c_i            

1     3   4   5

2     8   7   9



만약 인덱스의 이름과 열의 이름이 겹치는 경우에는 열의 이름이 우선순위가 높다.

이 경우 사용자가 인덱스를 query 표현식에서 사용하길 원하다면, 'index'를 인식자로서 사용하면 된다.


열의 레이블명과 인덱스 객체명이 동일할 시 우선순위를 보여주는 예)

# pandas와 numpy의 import

In[2]: import pandas as pd

In[3]: import numpy as np


# 예제용 배열 선언 및 인덱스 이름 명명

In[11]: ex_df=pd.DataFrame([[0,1,2], [3,4,5], [8,7,9]], columns=['c0','c1','c2'])

In[12]: ex_df.index.name='c0'

In[13]: ex_df

Out[13]: 

    c0  c1  c2

c0            

0    0   1   2

1    3   4   5

2    8   7   9


# 인덱스 객체의 이름과 열의 이름이 같을 시 우선순위를 보여주는 예

In[14]: ex_df.query('c0<2')

Out[14]: 

    c0  c1  c2

c0            

0    0   1   2


In[15]: ex_df.query('index<2')

Out[15]: 

    c0  c1  c2

c0            

0    0   1   2

1    3   4   5


참고사항

  만약 사용자가 열의 이름을 index로 설정하였다면, 인덱스 객체를 ilevel_0로 참조할 수 있다.

  그러나 이런 상황에서는 열의 이름을 다시 설정하는 것을 고려하는 편이 더 낫다. 

 


 멀티인덱스에서의 사용 예제

멀티인덱스를 사용 했을 경우에도 query 메서드가 적용이 가능하다.

아래 예제는 멀티인덱스에서의 이름 명을 지정했을 경우와 지정하지 않았을 경우에 query메서드를 적용한 예제를 보여준다.


멀티인덱스에서의 query 메서드 적용 예)

# pandas와 numpy의 import

In[2]: import pandas as pd

In[3]: import numpy as np


# 예제용 배열 선언 및 인덱스 이름 명명

In[16]: index_mul=pd.MultiIndex.from_tuples([('a1','b1'),('a1','b2'),('a2','b1'),('a2','b2')]) 

In[17]: ex_df_mul=pd.DataFrame([[0,1,2],[3,4,5],[6,7,8],[9,10,11]],index=index_mul)

In[18]: ex_df_mul.index.names=['L1','L2'] # 인덱스 이름 명명

In[19]: ex_df_mul

Out[19]: 

       0   1   2

L1 L2           

a1 b1  0   1   2

   b2  3   4   5

a2 b1  6   7   8

   b2  9  10  11


# 멀티인덱스에서의 query 사용

In[20]: ex_df_mul.query(' L1=="a1" ')

Out[20]: 

       0  1  2

L1 L2         

a1 b1  0  1  2

   b2  3  4  5


# 멀티인덱스 이름 초기화시 query 사용

n[21]: ex_df_mul.index.names=[None, None]  # 멀티인덱스 이름 초기화

n[22]: ex_df_mul.query('ilevel_0=="a1"')

Out[22]: 

       0  1  2

a1 b1  0  1  2

   b2  3  4  5

 

ilevel_0은 0번째 index 단계를 의미한다.



 in 및 not in 연산자의 사용 예제


in과 not in 연산자

query()는 또한 파이썬에서 제공하는 in과 not in 비교연산자를 지원한다. 

isin 메서드를 사용하는 것과 거의 동등한 결과를 도출한다. 


query 메서드에서의 in 및 not in 연산자 적용 예)

# pandas와 numpy의 import

In[2]: import pandas as pd

In[3]: import numpy as np


# 예제용 배열 선언 

In[23]: ex_df=pd.DataFrame([[0,1,3], [1,2,4], [2,3,6]], index=['r0','r1','r2'], columns=['c0','c1','c2'])

In[24]: ex_df

Out[24]: 

    c0  c1  c2

r0   0   1   3

r1   1   2   4

r2   2   3   6


# query에서의 in과 not in 사용 예제

In[25]: ex_df.query('c0 in c1')

Out[25]: 

    c0  c1  c2

r1   1   2   4

r2   2   3   6


In[26]: ex_df.query('c0 not in c1')

Out[26]: 

    c0  c1  c2

r0   0   1   3



참고사항

  아래 내용들은 TMI 이므로 굳이 몰라도 될 듯 하다.

  query() 메서드에서 문자열 표현식을 입력받는 것은 기본적으로 numexpr을 사용한다. 

  그러나 numexpr는 in과 not in 연산자를 제공하지 않는다. 

  즉, 표현식에서 in/not in 평범한 파이썬 문법이다.

  예를들어 아래 표현식에서

  ex_df.query('c0 in c1 + c2 + c3')

  in 연산은 평범한 파이썬 문법으로 처리되고 c1 + c2 + c3는 numexpr으로 처리된다. 

  즉, 기본적으로 어느 연산이건 numexpr으로 처리가 된다고 생각하면 된다.



list 객체와 == / != 연산자의 사용

==/!=연산자를 사용하여 값들의 리스트(list)를 비교하는 것은 in과 not in 과 유사하게 작동한다.

  ○ 아래 예제를 살펴보면 두 연산 결과가 위의 예제와 동일한 것을 확인할 수 있다.


query 메서드에서의 리스트에 == 및 != 연산자 적용 예)

# pandas와 numpy의 import

In[2]: import pandas as pd

In[3]: import numpy as np


# 예제용 배열 선언 

In[27]: ex_df=pd.DataFrame([[0,1,3], [1,2,4], [2,3,6]], index=['r0','r1','r2'], columns=['c0','c1','c2'])

In[28]: ex_df

Out[28]: 

    c0  c1  c2

r0   0   1   3

r1   1   2   4

r2   2   3   6


# query에서의 in과 not in 사용 예제

In[29]: ex_df.query('c0 == [1, 2, 3]')

Out[29]: 

    c0  c1  c2

r1   1   2   4

r2   2   3   6


In[30]: ex_df.query('c0 != [1, 2, 3]')

Out[30]: 

    c0  c1  c2

r0   0   1   3



~/not 연산자 

사용자는 not 혹은 ~연산자를 사용한 불린 표현식을 사용할 수 있다. 

  ○ 아래 예제는 not/~ 연산자를 사용한 예제이다.


query 메서드에서의 ~/not 연산자 적용 예)

# pandas와 numpy의 import

In[2]: import pandas as pd

In[3]: import numpy as np


# 예제용 배열 선언 

In[31]: ex_df=pd.DataFrame([[0,1,3, True], [1,2,4, False], [2,3,6, True]], index=['r0','r1','r2'], columns=['c0','c1','c2','c_bool'])

In[32]: ex_df

Out[32]: 

    c0  c1  c2  c_bool

r0   0   1   3    True

r1   1   2   4   False

r2   2   3   6    True


# ~/not 연산 사용 예제

In[33]: ex_df.query('c_bool')

Out[33]: 

    c0  c1  c2  c_bool

r0   0   1   3    True

r2   2   3   6    True


# 예제용 배열 선언 

In[34]: ex_df.query('~c_bool')

Out[34]: 

    c0  c1  c2  c_bool

r1   1   2   4   False


In[35]: ex_df.query('not c_bool')

Out[35]: 

    c0  c1  c2  c_bool

r1   1   2   4   False


위의 예제들을 적절히 조합하면 복잡한 조건식도 사용하는 것이 가능하다.



 query 메서드 세부 옵션


 DataFrame.query(self, expr, inplace=False, **kwargs)

문자열로 구성된 불린 표현식을 사용하여 DataFrame의 열을 선택한다.


expr: str

연산을 수행하기 위한 query 문자열을 입력받는다.

사용자는 @ 문자를 앞에 붙임으로써 환경변수를 참조할 수 있다.

  -@a+b

공백을 포함하는 열 이름은 백틱(`)으로 묶어서 참조 할 수 있다.

예를들어 만약 열중 하나가 a a와 b를 사용하여 더하기를 원한다면 사용자는 query표현식에 `a a` + b라 입력하면된다.

※ 백틱은 따옴표(')와 다르므로 주의하자.


inplace: bool

query가 데이터를 수정하거나 혹은 수정된 카피를 반환할지 여부를 결정한다.

 

**kwarys

eval() 메서드에 대한 자료를 참고하자. 



참고사항

  표현식에 의한 평가결과 결과는 처음에는 DataFrame.loc에 전달된다. 

  만약 다차원 키(key)때문에 실패한다면, 결과는 DataFrame.__getitem__()에 전달된다.


  이 메서드는 전달된 query를 평가하기 위해 최상위 단계인 eval() 함수를 사용한다. 


  query() 메서드는 기본적으로 약간 수정된 파이썬 문법을 사용한다. 

  예를들어 &와 |는 불린 연산자의 사촌격인 and와 or의 우선순위를 가진다.

  이것은 문법적으로 유효하나 의미론적으로는 다르다.


  사용자는 키워드 인자인 parser='python' 입력함으로써 표현식의 의미를 바꿀 수 있다.

  이것은 같은 표현식이 순수 python과 동일하게 만든다.

  마찬가지로 사용자는 engine='python'을 입력하여 백앤드처럼 파이썬 고유기능을 이용한 표현식을 사용할 수 있다.

  이것은 권장되지 않는데, numexpr 엔진을 사용하는 것에 비해 비효율적이다.


  DataFrame 인스턴스(instance)안에 내장되어 있는 DataFrame.index와 DataFrame.columns 어트리뷰트(attribute)는 query 네임스페이스에 기본적으로 내장되어있다. 

  그리고 이는 사용자에게 프레임에서의 열처럼 인덱스와 열을 처리할 수 있도록 도와준다.

  식별자(identifier) index는 프레임의 인덱스에대해 사용되어지고, 사용자는 또한 인덱스의 이름을 query에서 식별할 수 있게 사용할 수 있다.

  파이썬의 키워드들은 식별자로써 사용될 수 없다는 사실을 알고있도록 하자.



 

 

 

 

 참고자료

  https://pandas.pydata.org/pandas-docs/stable/user_guide/indexing.html

  https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.DataFrame.query.html

 

 

 

 



반응형

댓글