ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 10 minutes to pandas - Group by (split - apply - combine)
    데이터 분석/Pandas 2022. 3. 29. 23:00

    Group By 개요


    Splitting the data into groups based on some criteria

    Applying a function to each group independently 

    - Aggregation: 각 그룹에 대하여 요약통계를 처리할 수 있다.
    - Transformation: 그룹 특화 연산을 수행하고, 전체 데이터에 대해 그 값을 적용할 수 있다. 
    - Filtration: 그룹 단위 연산으로 T/F 를 평가한다. True 인 대상을 추출할 수 있다. 

    Combining the results into a data structure.

    split, apply, combine

     

     

    Splitting an object into groups


    Groupby 를 독립적으로 이해하는 것이 중요하다.

     

    주요기능

    # 컬럼명의 값 기준으로 그룹핑하기 
    grouped = df.groupby("A")
    grouped = df.groupby(["A", "B"])
    grouped = df.groupby("first")
    grouped = df.groupby(["first", "second"])
    grouped = df.groupby(["first", "A"])
    
    # 인덱스 명/위치를 통해 인덱스의 값을 기준으로 그룹핑하기
    grouped = df.groupby(level=0)
    grouped = df.groupby(level=["first", "second"])
    
    # 컬럼 및 인덱스의 값 기준으로 그룹핑하기 
    grouped = df.groupby([pd.Grouper(level=0), "A"])
    grouped = df.groupby([pd.Grouper(freq="1M", key="Date"), "Buyer"]).sum()
    
    # Date 컬럼으로 그룹핑할 경우, index 로 옮긴후 그룹핑하기 
    grouped = df.groupby([df.index.year, df.index.month])

     

    주의. 만약 그룹의 기준에 NaN 또는 NaT 가 있다면, 자동적으로 배제된다. 즉 NA 그룹이나 NaT 그룹은 없다!
    만약 NA 그룹이나 NaT 그룹이 필요하면 dropna = False 를 사용하자!

    참고. pd.Grouper 는 특히 datetime-like object 에 대한 다양한 기능을 제공한다. 필요할 경우 더 공부해보자. 

     

    부가기능

    # group by 속성 
    grouped = df.groupby("A", dropna=False)
    grouped = df.groupby("A", as_index=False)
    
    
    # Groupby Object 상세 확인
    grouped.groups #그룹 이름과 행의 인덱스 배열 딕셔너리
    grouped.ngroups # 몇 개의 그룹
    grouped.get_group("bar") # 'bar 라는 이름을 가지는 그룹 
    
    for name, group in grouped: #그룹 이름과 그룹의 DataFrame Chunk 
        print(name)
        print(group)

     

     

    Applying


    Aggregation

    각 그룹에 대해 연산 (주로 통계치 계산) 을 수행할 수 있다. 스프레드시트의 Pivot Table 기능과 흡사하다!
    주의. 그룹의 연산 대상에 NaN 값이 있을 경우 연산대상에서 제외된다.

    grouped = df.groupby("A")
    
    # 연산이 가능한 모든 컬럼에 대해서 다음 연산을 수행한다. 
    grouped.sum()
    grouped.mean()
    grouped.size()
    grouped.describe()
    grouped.nunique()
    grouped.nlargest(3)
    
    # 연산이 가능한 모든 컬럼에 대해서 연산을 1개 또는 N개 수행한다.
    grouped.aggregate(np.sum)
    grouped.aggregate([np.sum, np.mean, np.std])
    
    # 사용자정의 함수를 수행한다. 
    grouped.agg(lambda x: x.max() - x.min())
    grouped.agg([lambda x: x.max() - x.min(), lambda x: x.median() - x.mean()])
    
    # df 의 특정 컬럼에 대해서만 연산을 수애한다. 
    grouped["C"].agg([np.sum, np.mean, np.std])
    grouped[["C", "D"]].agg([np.sum, np.mean, np.std])
    
    # df 의 컬럼마다 다른 연산을 수행한다. 
    grouped.agg({"C": np.sum, "D": lambda x: np.std()})

     

     

    Transformation

    전체 데이터에 그룹 단위의 연산값을 활용하여 특정 값을 변환할 수 있다. 

    # z score : 그룹의 평균과 표준편차 값을 가지고 z score 를 구한다. 
    index = pd.date_range("10/1/1999", periods=1100)
    ts = pd.Series(np.random.normal(0.5, 2, 1100), index)
    grouped = ts.groupby(lambda x: x.year)
    grouped.transform(lambda x: (x - x.mean()) / x.std())
    
    # fillna : NA 를 각 그룹의 평균값으로 채운다. 
    grouped = df.groupby('A')
    grouped.transform(lambda x: x.fillna(x.mean()))
    grouped.ffill()

     

     

    Filteration

    특정 조건을 만족하는 subset 만 추출할 수 있다. 

    # 그룹에 속한 값의 합이 4 초과인 그룹만 남긴다. 
    sf = pd.Series([1, 2, 2, 3, 3, 3, 4, 4, 4, 4])
    sf.groupby(sf).filter(lambda x : x.sum() > 4)
    
    # 그룹 크기가 2 초과인 그룹만 남긴다.
    dff = pd.DataFrame({"A": np.arange(8), "B": list("aabbbbcc")})
    dff.groupby('B').filter(lambda x : len(x) > 2)

     

    응용


    Flexible Apply

    하나의 컬럼에 대해 값을 다양하게 변환하고 싶은 경우 다음과 같이 적용할 수 있다. 

    # A 컬럼 값을 기준으로 그룹핑한다. 그 중 C 컬럼에 대해 관심이 있다.
    grouped = df.groupby('A')['C']
    
    # group 을 인자로 받고, 새로운 DataFrame 을 제공하는 함수이다. 
    def f(group):
        return pd.DataFrame({'original': group,      # 원래값
                             'demeaned': group - group.mean()})   # 평균과의 거리(편차)
                             
                             
    # GroupBy Object 에 대해 f 함수를 호출한다.  
    grouped.apply(f)
    
    '''
       original  demeaned
    0 -0.575247 -0.215962
    1  0.254161  0.123181
    2 -1.143704 -0.784420
    3  0.215897  0.084917
    4  1.193555  1.552839
    '''

     

    Piping Function Calls

    Functions that take GroupBy objects can be chained together using a pipe method to allow for a cleaner, more readable syntax. 

    GroupBy Object 를 인자로 받아서 함수를 수행할 수 있다. 

    n = 1000
    df = pd.DataFrame(
        {
            "Store": np.random.choice(["Store_1", "Store_2"], n),
            "Product": np.random.choice(["Product_1", "Product_2"], n),
            "Revenue": (np.random.random(n) * 50 + 10).round(2),
            "Quantity": np.random.randint(1, 10, size=n),
        }
    )
    '''
         Store    Product  Revenue  Quantity
    0  Store_2  Product_1    26.12         1
    1  Store_2  Product_1    28.86         1
    '''
    
    # 여러 컬럼의 값에 대한 연산을 활용하여 결과를 제공한다. 
    df.groupby(["Store", "Product"]).pipe(
        lambda grp: grp.Revenue.sum() / grp.Quantity.sum()
        ).unstack().round(2)
        
    '''
    Product  Product_1  Product_2
    Store                        
    Store_1       6.82       7.05
    Store_2       6.30       6.64
    '''
    
    # GroupBy Object 에 대해 사용자 정의 함수를 처리할 수 있다. 
    def mean(groupby):
        return groupby.mean()
        
    df.groupby(["Store", "Product"]).pipe(mean)
    
    '''
                         Revenue  Quantity
    Store   Product                       
    Store_1 Product_1  34.622727  5.075758
            Product_2  35.482815  5.029630
    Store_2 Product_1  32.972837  5.237589
            Product_2  34.684360  5.224000
    '''

     

     

     

    댓글

Designed by Tistory.