사용자가 Pandas DataFrame 또는 Series 객체에 여러 필터를 적용하려는 시나리오가 있습니다. 본질적으로 사용자가 런타임에 지정하는 여러 필터링 (비교 작업)을 효율적으로 연결하고 싶습니다.
필터는 추가되어야합니다 (일명 적용되는 각 필터는 결과가 좁아 야 함).
현재 사용하고 reindex()
있지만 매번 새 객체를 만들고 기본 데이터를 복사합니다 (문서를 올바르게 이해하면). 따라서 큰 Series 또는 DataFrame을 필터링 할 때 실제로 비효율적 일 수 있습니다.
내가 사용하는 것을 생각하고 apply()
, map()
또는 이와 유사한 일이 더 좋을 수 있습니다. 나는 여전히 팬더를 처음 접했지만 여전히 모든 것을 머리로 감싸려고합니다.
TL; DR
다음 형식의 사전을 가져 와서 각 작업을 주어진 Series 객체에 적용하고 ‘필터링 된’Series 객체를 반환하고 싶습니다.
relops = {'>=': [1], '<=': [1]}
긴 예
나는 현재 가지고있는 것의 예부터 시작하여 단일 Series 객체를 필터링합니다. 아래는 현재 사용중인 기능입니다.
def apply_relops(series, relops):
"""
Pass dictionary of relational operators to perform on given series object
"""
for op, vals in relops.iteritems():
op_func = ops[op]
for val in vals:
filtered = op_func(series, val)
series = series.reindex(series[filtered])
return series
사용자는 수행하려는 작업을 사전에 제공합니다.
>>> df = pandas.DataFrame({'col1': [0, 1, 2], 'col2': [10, 11, 12]})
>>> print df
>>> print df
col1 col2
0 0 10
1 1 11
2 2 12
>>> from operator import le, ge
>>> ops ={'>=': ge, '<=': le}
>>> apply_relops(df['col1'], {'>=': [1]})
col1
1 1
2 2
Name: col1
>>> apply_relops(df['col1'], relops = {'>=': [1], '<=': [1]})
col1
1 1
Name: col1
다시 말하지만, 위의 접근 방식의 ‘문제’는 중간 단계의 데이터를 불필요하게 복사 할 수 있다고 생각합니다.
또한 전달 된 사전에 연산자에 열을 포함하고 입력 사전을 기반으로 전체 DataFrame을 필터링 할 수 있도록 이것을 확장하고 싶습니다. 그러나 Series에 작동하는 모든 것을 DataFrame으로 쉽게 확장 할 수 있다고 가정합니다.
답변
팬더 (및 numpy)는 부울 인덱싱을 허용 하므로 훨씬 효율적입니다.
In [11]: df.loc[df['col1'] >= 1, 'col1']
Out[11]:
1 1
2 2
Name: col1
In [12]: df[df['col1'] >= 1]
Out[12]:
col1 col2
1 1 11
2 2 12
In [13]: df[(df['col1'] >= 1) & (df['col1'] <=1 )]
Out[13]:
col1 col2
1 1 11
이를 위해 도우미 함수를 작성하려면 다음 행을 따라 무언가를 고려하십시오.
In [14]: def b(x, col, op, n):
return op(x[col],n)
In [15]: def f(x, *b):
return x[(np.logical_and(*b))]
In [16]: b1 = b(df, 'col1', ge, 1)
In [17]: b2 = b(df, 'col1', le, 1)
In [18]: f(df, b1, b2)
Out[18]:
col1 col2
1 1 11
업데이트 : pandas 0.13에는 이러한 종류의 사용 사례에 대한 쿼리 방법 이 있습니다. 열 이름이 다음 식별자의 유효한 식별자라고 가정하면 (큰 배후에서 numexpr 을 사용 하므로 큰 프레임에 더 효율적일 수 있습니다 ) :
In [21]: df.query('col1 <= 1 & 1 <= col1')
Out[21]:
col1 col2
1 1 11
답변
연쇄 조건은 긴 줄을 생성하며, 이는 pep8에 의해 권장되지 않습니다. .query 메소드를 사용하면 문자열이 강력하게 사용되지만 강력하지는 않지만 강력하지는 않습니다.
각 필터가 설치되면 한 가지 접근 방식은
import numpy as np
import functools
def conjunction(*conditions):
return functools.reduce(np.logical_and, conditions)
c_1 = data.col1 == True
c_2 = data.col2 < 64
c_3 = data.col3 != 4
data_filtered = data[conjunction(c1,c2,c3)]
np.logical은 빠르게 작동하지만 functools.reduce에 의해 처리되는 두 개 이상의 인수를 사용하지 않습니다.
여기에는 여전히 일부 중복성이 있습니다. a) 전역 수준에서 바로 가기가 발생하지 않습니다. b) 각 개별 조건은 전체 초기 데이터에서 실행됩니다. 아직도, 나는 이것이 많은 응용 프로그램에 충분할 것으로 기대하며 매우 읽기 쉽습니다.
np.logical_or
대신 다음 을 사용하여 분리를 수행 할 수도 있습니다 (조건 중 하나만 참이어야 함) .
import numpy as np
import functools
def disjunction(*conditions):
return functools.reduce(np.logical_or, conditions)
c_1 = data.col1 == True
c_2 = data.col2 < 64
c_3 = data.col3 != 4
data_filtered = data[disjunction(c1,c2,c3)]
답변
가장 간단한 솔루션 :
사용하다:
filtered_df = df[(df['col1'] >= 1) & (df['col1'] <= 5)]
다른 예제 , Feb-2018에 속하는 값에 대해 데이터 프레임을 필터링하려면 아래 코드를 사용하십시오.
filtered_df = df[(df['year'] == 2018) & (df['month'] == 2)]
답변
pandas 0.22 update 이므로 다음과 같은 비교 옵션을 사용할 수 있습니다.
- gt (보다 큼)
- lt (보다 작음)
- eq (같음)
- ne (같지 않음)
- ge (이상)
그리고 더 많은. 이 함수는 부울 배열을 반환합니다. 우리가 그것들을 어떻게 사용할 수 있는지 보자.
# sample data
df = pd.DataFrame({'col1': [0, 1, 2,3,4,5], 'col2': [10, 11, 12,13,14,15]})
# get values from col1 greater than or equals to 1
df.loc[df['col1'].ge(1),'col1']
1 1
2 2
3 3
4 4
5 5
# where co11 values is better 0 and 2
df.loc[df['col1'].between(0,2)]
col1 col2
0 0 10
1 1 11
2 2 12
# where col1 > 1
df.loc[df['col1'].gt(1)]
col1 col2
2 2 12
3 3 13
4 4 14
5 5 15
답변
왜 이러지?
def filt_spec(df, col, val, op):
import operator
ops = {'eq': operator.eq, 'neq': operator.ne, 'gt': operator.gt, 'ge': operator.ge, 'lt': operator.lt, 'le': operator.le}
return df[ops[op](df[col], val)]
pandas.DataFrame.filt_spec = filt_spec
데모:
df = pd.DataFrame({'a': [1,2,3,4,5], 'b':[5,4,3,2,1]})
df.filt_spec('a', 2, 'ge')
결과:
a b
1 2 4
2 3 3
3 4 2
4 5 1
열 ‘a’가 a> = 2 인 경우 필터링되었음을 알 수 있습니다.
이것은 연산자 체인보다 약간 빠릅니다 (타이핑 시간이 아니라 성능). 물론 파일의 맨 위에 가져 오기를 넣을 수 있습니다.
답변
또한 목록에 없거나 반복 가능한 열 값을 기반으로 행을 선택할 수 있습니다. 이전과 같이 부울 변수를 만들지 만 이제 ~를 앞에 두어 부울 변수를 무효화합니다.
예를 들어
list = [1, 0]
df[df.col1.isin(list)]
답변
