[Pandas] 그룹화된 데이터프레임 필터링하기

반응형
    반응형

    apply를 이용하면 그룹화한 데이터프레임에 lambda함수를 쓸 수 있었습니다. 그런데 람다함수로 부등식을 적용하게 되면 bool값으로 처리가 될 것이지만 True,False를 알려고 전처리를 하진 않습니다. 실제로 True,False를 반영하여 값이 걸러져 나와주어야 합니다.

     

    그룹화된 데이터프레임을 True, False로 분류하였는데 이를 반영하려면 어떻게 해야할까요?
    바로 filter() 를 쓰면 됩니다. 데이터프레임의 group화를 한 상태에서 그룹화된 데이터프레임마다 True와 False로 구분할 수 있는데 이를 데이터프레임에 반영해줍니다.

     

    'Learning Pandas'의 예제를 가져오겠습니다.

    import pandas as pd
    import numpy as np
    df = pd.DataFrame({'Label':list('AABCCC'),'Values':[1,2,3,4,np.nan,8]})
    df

     

    람다함수 만들기

    filter에 앞서 람다함수를 이용한 True,False가 어떻게 나타나는지 apply를 통해 확인해보겠습니다.

    f = lambda x: x.Values.count()>1
    df.groupby('Label').apply(f)

     

    apply를 적용하면 각 라벨별로 bool형식으로 나타나게 됩니다.
    bool 값을 활용해 데이터프레임에 반영하여 나타나게 하기 위해 filter를 사용하게 됩니다.

    filter 사용하기

    2가지 예제를 보이겠습니다. 형식은 다 같습니다. 

    람다함수를 정의한 후 그룹화된 데이터프레임에 filter를 해주면 됩니다.

    # 라벨 갯수 1보다 큰 경우만 출력
    f = lambda x : x.Values.count()>1
    df.groupby('Label').filter(f)

     

    # NaN drop
    f = lambda x: x.Values.isnull().sum()==0
    df.groupby('Label').filter(f)

     

    실제로 각 라벨별로 NaN 갯수합을 구해보면 다음과 같이 나옵니다.

    for name, grouped in df.groupby('Label'):
    print(grouped.Values.isnull().sum())

    C 라벨만 람다함수를 적용하면 False라서 필터링 되었습니다.

     

    평균 filter

    filter를 쓰려면 라벨별로 값을 찾는 건지 라벨 안에 각각의 값으로 값을 찾는지 명확히 해야합니다.

    grouped = df.groupby('Label')
    # 전체평균
    mean = grouped.mean().mean()
    # 라벨별 평균-전체평균
    f = lambda x : abs(x.Values.mean()-mean)>2.0
    df.groupby('Label').filter(f)

    라벨별 평균에서 전체평균을 빼고 그 값에서 2.0 이 큰 경우에만 출력하도록 요청을 했습니다.
    보시는바와 같이 C 라벨의 값만 나왔습니다. 이는 C 라벨의 각 값을 얘기하는게 아니라 C라벨이 전체평균에 2보다 크다는 것을 의미합니다.

     

    실제로 각 라벨별로 평균을 구해보면 다음과 같습니다.

    for name,grouped in df.groupby('Label'):
        print(grouped.Values.mean())

    전체평균은 3.5가 나오는데 6-3.5>2 이므로 C라벨만 해당되게 됩니다. filter가 잘 되었습니다.

     

    만약 나오게 하고 싶은 값이 각 라벨의 평균이라면 agg로 평균만 표시한 후 filter를 진행합니다. 약간 복잡합니다.

    grouped=df.groupby('Label')
    ex = grouped.agg([np.mean])
    ex_grouped=ex.groupby('Label')
    mean = ex_grouped.mean().mean()
    f = lambda x : abs(x-mean)>2.0
    ex_grouped.filter(f)

     

    filter 후 생략된 값 확인하기

    어떤 값이 생략됐는지 확인하기 위한 방법입니다. 위에서 한 예 중에서 하나인 Values.count()>1 인 경우로 보겠습니다.

    df에는 B의 값 갯수가 1개이므로 filter 처리를 하면 위에서 보인것처럼 생략되어 됩니다.
    그런데 dropna=False 를 적용하면 없어져야 할 B를 가지고 옵니다.

    하지만 B 는 NaN으로 처리되어 나타납니다.

    f = lambda x: x.Values.count()>1
    df.groupby('Label').filter(f,dropna=False)

     

    마치며

    filter를 사용하면 람다함수로 이루어진 부등식을 그룹화된 데이터프레임에 쓸 수 있었습니다.
    라벨링이 잘 되어 그룹화가 가능하다면 언제든지 부등식을 한꺼번에 적용할 수 있어 편리하게 데이터전처리를 할 수 있을겁니다.

     

    관련 포스팅
    [Pandas] 같은 범주로 묶기(groupby)

    [Pandas] groupby 데이터프레임에 함수 적용하기(transform)

    [Pandas] 함수 적용하기(map,apply, applymap)

    댓글

    Designed by JB FACTORY

    ....