본문 바로가기
파이썬/파이썬 스터디

파이썬 pandas(판다스) groupby - 시간에 따라 묶기

by davi_kr 2024. 8. 4.

목차

    반응형

    결과물

    년월, 결제수단(payment)에 따라 총 금액을 볼 수 있고 해당 년월에 특정 자치구에서 나온 값들도 같이 볼 수 있습니다.

    데이터 둘러보기

    groupby를 어떻게 활용할 수 있는지, 자세히 다뤄보기 위해 데이터를 먼저 둘러봅니다.

    이용할 데이터는 택시 관련 정보입니다.

    import pandas as pd
    import seaborn as sns
    import numpy as np
    df = sns.load_dataset('taxis')
    df.info()

     

    df.head(5)

     

    위 데이터는 상차, 하차 시간, 승객 수, 거리, 운임비, 팁, 톨비, 총 비용, 색상, 결제수단, 상차 지역, 하차 지역, 상차 자치구, 하차 자치구 정보로 구성되어 있습니다.

     

    df.isnull().sum()

    결측치는 수량이 얼마나 있는지 확인해봅니다.

     

    df['payment'].unique()

    결측치가 있는 열은 유니크 값이 어떻게 구성되어 있는지도 확인해봅니다.

     

    오늘은 groupby 공부하려는 거라.. 그냥 결측치가 있는 행들은 다 제외시키겠습니다.

     

    # df에서 빈 값이 있는 행들은 모두 제외함
    df1 = df.dropna().copy()
    # 빈 값이 있는 행이 있을지, 전체적으로 합산해서 확인
    df1.isnull().sum().sum()

     

    groupby 작동 원리

    groupby는 말 그대로 묶어주는 기능을 합니다. 

    예를 들어, payment에 따라 발생한 total의 합이 궁금하다면?

    아래와 같이 작성하면 됩니다.

    df1.groupby('payment')[['total']].sum()

     

    쉽게 생각하면 groupby 함수는 먼저 payment열의 값들을 기준으로 분리합니다.

    위에서 cash, credit card, nan이었으나 nan은 전부 날렸기 때문에 기준은 cash와 credit card가 됩니다.

    분리한 상태에서 sum()을 적용합니다.

    그리고 다시 칩니다.

     

    이 과정을 split → apply → combine으로 이해하면 됩니다.

    따라서 groupby까지만 사용한 경우엔 split 까지만 해둔 상태라고 보실 수 있겠습니다.

    그때는 아래처럼 결과값도 그냥 groupby object라고만 노출됩니다.

    df1.groupby('payment')

     

    apply할 값에는 sum 외에도 다양한 수치를 계산하는 함수들을 사용할 수 있으며, 직접 만든 함수도 쓸 수 있습니다.

    함수 이름 설명
    sum 합 계산
    mean, median, mod 평균, 중위값, 최빈값 계산
    max, min 최대, 최소값 계산
    count, nunique, size NaN 제외한 값, 유니크 값, NaN 포함한 값 세기
    std, var 표준편차, 분산 계산

     

     

    시간에 따라 그룹핑하기

    시간에 따라 그룹핑을 해보기 위해 먼저 시간 열을 추가하겠습니다.

    df1['year'] = df1['pickup'].dt.year
    # 상반기, 하반기도 추가
    def determine_half_year(date):
        year = date.year
        month = date.month
        if month <= 6:
            return f"{year}H1"
        else:
            return f"{year}H2"
    
    df1['half'] = df1['pickup'].apply(determine_half_year)
    df1['quarter'] = df1['pickup'].dt.to_period('Q')
    df1['year_month'] = df1['pickup'].dt.to_period('M')
    df1['date'] = df1['pickup'].dt.to_period('D')
    
    df1.head(5)

     

    기존에 했던 그룹핑에 년월 기준을 추가해보겠습니다.

    df1.groupby(['year_month','payment'])['total'].sum()

    데이터가 아쉽네요^^;;  같은 해 2월 3월 뿐이었네요...

     

    특정 열의 값들을 열로 바꾸기

    구하다보면 같은 열에 있는 데이터들의 수량을 각각의 열로 변환해서 보고 싶을 때가 있습니다.

    여기선 unstack과 pivot_table을 사용해봤습니다.

     

    먼저 년월 기준으로 값을 추출하기 위해 위에서 했던 것과 동일한 결과 값에 index만 리셋했습니다.

    grouped_df1 = df1.groupby(['year_month','payment']).agg({
        'total':'sum'
    }).reset_index()

     

    pickup_borough의 값들을 기준으로 새로 열을 만들어봤습니다. 

    grouped_df_pickup_borough = df1.groupby(['year_month','payment','pickup_borough']
                                            ).agg({'total':'sum'}).unstack(fill_value=0)

     

    원래는 이 상태 그대로 merge 해보려고 했는데, Not allowed to merge between different levels. (1 levels on the left, 2 on the right) (1 levels on the left, 2 on the right) 오류가 났습니다.

     

     

    문제를 해결하고자 pivot_table 기능을 사용해봤습니다.

    grouped_df_pickup_borough = df1.pivot_table(index=['year_month', 'payment']
                                                , columns='pickup_borough'
                                                , values='total'
                                                , aggfunc='sum'
                                                , fill_value=0).reset_index()

     

    result = grouped_df1.merge(grouped_df_pickup_borough
                               , how='inner'
                               , on=['year_month','payment'])

    결과물이 잘 나왔습니다. 해당 년월에 사용한 현금, 신용카드 기준으로 총 금액이 얼마인지 특정 자치구에서는 얼마가 나왔는지를 한눈에 볼 수 있게 됐습니다.

    반응형

    댓글