복붙노트

[PYTHON] 팬더 데이터 프레임을 동적으로 필터링하기

PYTHON

팬더 데이터 프레임을 동적으로 필터링하기

3 열에 대한 임계 값을 사용하여 팬더 데이터 프레임을 필터링하려고합니다.

import pandas as pd
df = pd.DataFrame({"A" : [6, 2, 10, -5, 3],
                   "B" : [2, 5, 3, 2, 6],
                   "C" : [-5, 2, 1, 8, 2]})
df = df.loc[(df.A > 0) & (df.B > 2) & (df.C > -1)].reset_index(drop = True)

df
    A  B  C
0   2  5  2
1  10  3  1
2   3  6  2

그러나 필자는 사전에서 컬럼의 이름과 임계 값을 알려주는 함수 내에서이 작업을 수행하려고합니다. 여기에 내 첫 번째 시도는 괜찮습니다. 기본적으로 cond 변수 안에 필터를 넣고 실행합니다.

df = pd.DataFrame({"A" : [6, 2, 10, -5, 3],
                   "B" : [2, 5, 3, 2, 6],
                   "C" : [-5, 2, 1, 8, 2]})
limits_dic = {"A" : 0, "B" : 2, "C" : -1}
cond = "df = df.loc["
for key in limits_dic.keys():
    cond += "(df." + key + " > " + str(limits_dic[key])+ ") & "
cond = cond[:-2] + "].reset_index(drop = True)"
exec(cond)
df
    A  B  C
0   2  5  2
1  10  3  1
2   3  6  2

이제 마침내 나는 모든 것을 함수 안에 넣었고 작동을 멈췄다. (아마도 exec 함수는 함수 내부에서 사용되는 것을 좋아하지 않을 것이다!) :

df = pd.DataFrame({"A" : [6, 2, 10, -5, 3],
                   "B" : [2, 5, 3, 2, 6],
                   "C" : [-5, 2, 1, 8, 2]})
limits_dic = {"A" : 0, "B" : 2, "C" : -1}
def filtering(df, limits_dic):
    cond = "df = df.loc["
    for key in limits_dic.keys():
        cond += "(df." + key + " > " + str(limits_dic[key])+ ") & "
    cond = cond[:-2] + "].reset_index(drop = True)"
    exec(cond)
    return(df)

df = filtering(df, limits_dic)
df
    A  B  C
0   6  2 -5
1   2  5  2
2  10  3  1
3  -5  2  8
4   3  6  2

exec 함수는 함수 내에서 사용될 때 다르게 작동하지만 문제를 해결하는 방법을 알지 못했습니다. 또한, 나는 두 가지 입력 주어진 필터링을 수행하는 함수를 정의하는 더 우아한 방법이 있어야합니다 궁금 해서요 : 1) df 및 2) limits_dic = { "A": 0, "B": 2, "C": - 1}. 이것에 대한 어떤 생각이라도 고맙게 생각합니다.

해결법

  1. ==============================

    1.동적 쿼리를 작성하려는 경우 더 쉬운 방법이 있습니다. 목록 이해력과 str.join을 사용하는 방법은 다음과 같습니다.

    동적 쿼리를 작성하려는 경우 더 쉬운 방법이 있습니다. 목록 이해력과 str.join을 사용하는 방법은 다음과 같습니다.

    query = ' & '.join(['{}>{}'.format(k, v) for k, v in limits_dic.items()])
    

    또는, 파이썬 3.6 +와 f - 문자열을 사용하여,

    query = ' & '.join([f'{k}>{v}' for k, v in limits_dic.items()])
    

    print(query)
    
    'A>0 & C>-1 & B>2'
    

    쿼리 문자열을 df.query에 전달합니다. 이는 다음과 같은 목적을위한 것입니다.

    out = df.query(query)
    print(out)
    
        A  B  C
    1   2  5  2
    2  10  3  1
    4   3  6  2
    

    또한 부울 마스크를 얻고 자한다면 df.eval을 사용할 수 있습니다. 그리고 나서 인덱스는 그 후에 간단 해집니다 :

    mask = df.eval(query)
    print(mask)
    
    0    False
    1     True
    2     True
    3    False
    4     True
    dtype: bool
    
    out = df[mask]
    print(out)
    
        A  B  C
    1   2  5  2
    2  10  3  1
    4   3  6  2
    

    문자열 데이터를 사용하는 열을 쿼리해야하는 경우 위의 코드는 약간 수정해야합니다.

    다음을 고려하십시오 (이 답변의 데이터).

    df = pd.DataFrame({'gender':list('MMMFFF'),
                       'height':[4,5,4,5,5,4],
                       'age':[70,80,90,40,2,3]})
    
    print (df)
      gender  height  age
    0      M       4   70
    1      M       5   80
    2      M       4   90
    3      F       5   40
    4      F       5    2
    5      F       4    3
    

    그리고 열, 연산자 및 값의 목록 :

    column = ['height', 'age', 'gender']
    equal = ['>', '>', '==']
    condition = [1.68, 20, 'F']
    

    적절한 수정은 다음과 같습니다.

    query = ' & '.join(f'{i} {j} {repr(k)}' for i, j, k in zip(column, equal, condition))
    df.query(query)
    
       age gender  height
    3   40      F       5
    
  2. from https://stackoverflow.com/questions/45925327/dynamically-filtering-a-pandas-dataframe by cc-by-sa and MIT license