본문 바로가기
코딩

Python Pandas 데이터 분석 groupby 사용법

by 눈표범  2021. 7. 15.

파이썬에서 데이터 분석, 처리를 할 때 많이 팬더스(Pandas) 사용합니다.

그중에서 groupby를 사용해야 하는 경우가 있어 정리를 하게 되었습니다.

 

Python Pandas groupby

 

# 라이브러리 import

import pandas as pd
import numpy as np

 

 

DataFrame으로 샘플 데이터 작성

df = pd.DataFrame({
'city': ['부산', '부산', '부산', '부산', '서울', '서울', '서울'],
'fruits': ['apple', 'orange', 'banana', 'banana', 'apple', 'apple', 'banana'],
'price': [100, 200, 250, 300, 150, 200, 400],
'quantity': [1, 2, 3, 4, 5, 6, 7]
})
df

 

   city  fruits  price  quantity
 0  부산  apple  100  1
 1  부산  orange  200  2
 2  부산  banana  250  3
 3  부산  banana  300  4
 4  서울  apple  150  5
 5  서울  apple  200  6
 6  서울  banana  400  7

 

groupby 사용 방법

같은 값을 하나로 묶어 통계 또는 집계 결과를 얻기 위해 사용하는 것이 groupby입니다.

예를 들어 도시(city) 별로 가격(price) 평균을 구하고 싶은 경우 다음과 같이 groupby를 사용하여 평균값을 구할 수 있습니다.

평균값을 구해주는 메서드로 mean을 사용합니다.

df.groupby('city').mean()

 

   price  quantity
 city    
 부산  212.5  2.5
 서울  250.0  6.0

 

그룹 지정은 여러 개를 지정할 수도 있습니다.

도시(city)와 과일(fruits)로 평균을 구해보겠습니다.

df.groupby(['city', 'fruits']).mean()

 

     price  quantity
 city  fruits    
 부산  apple  100.0  1.0
 banana  275.0  3.5
 orange  200.0  2.0
 서울  apple  175.0  5.5
 banana  400.0  7.0

 

도시별로 그룹화하고 다시 과일 종류별로 그룹이 된 평균값을 얻을 수 있습니다.

 

groupby를 사용하면 기본으로 그룹 라벨이 index가 됩니다.

index를 사용하고 싶은 않은 경우에는 as_index=False 를 설정하면 됩니다.

df.groupby(['city''fruits'], as_index=False).mean()

 

   city  fruits  price  quantity
 0  부산  apple  100.0  1.0
 1  부산  banana  275.0  3.5
 2  부산  orange  200.0  2.0
 3  서울  apple  175.0  5.5
 4  서울  banana  400.0  7.0

 

GroupBy 오브젝트 특성

 

get_group()

그룹 안에 데이터를 확인하고 싶은 경우 사용합니다.

df.groupby('city').get_group('부산')

 

   city  fruits  price  quantity
 0  부산  apple  100  1
 1  부산  orange  200  2
 2  부산  banana  250  3
 3  부산  banana  300  4

 

size()

각 그룹의 사이즈를 취득할 수 있습니다.

df.groupby('city').size()

>>>

city

부산 4

서울 3

dtype: int64

 

size() 결과는 Series 이라는 1차원 배열 오브젝트로 반환합니다.

반환된 배열에서 특정 그룹의 사이즈만을 취득할 수 있습니다.

df.groupby('city').size()['부산']

>>>

4

 

 

 

Aggregation

GroupBy.mean()처럼 그룹별로 결과를 얻는 조작을 Aggregation이라고 부릅니다.

GroupBy 오브젝트에는 Aggregation에 사용할 수 있는 함수가 있습니다.

Aggregation를 사용하고 싶은 경우에는 agg()를 사용해서 처리할 수 있습니다.

df.groupby('city').agg(np.mean)

 

   price  quantity
 city    
 부산  212.5  2.5
 서울  250.0  6.0

 

agg에 mean()을 사용하여 도시별 가격과 수량의 평균값을 구했습니다.

만약 가격의 평균과 수량의 합계를 동시에 구하고 싶은 경우에는 어떻게 해야 할까요?

agg를 사용하여 동시에 처리할 수 있습니다.

def my_mean(s): 
          return np.mean(s)

df.groupby('city').agg({'price': my_mean, 'quantity': np.sum})

 

   price  quantity
 city    
 부산  212.5  10
 서울  250.0  18

 

apply

Aggregation을 사용하여 그룹 별로 결과를 얻을 수 있지만 더욱 활용하기 편리한 결과를 만들고 싶을 때 apply를 사용합니다.

apply를 사용하면 그룹별로 DataFrame를 사용할 수 있습니다.

 

apply 결과를 스칼라로 반환한 경우

・groupby로 작성한 lable이 row index가 됨.
・행수는 그룹수와 동일
・as_index 적용 안됨
df.groupby(['city''fruits'], as_index=False).apply(lambda d: (d.price * d.quantity).sum())

 

city      fruits 

부산     apple     100

          banana   1950

          orange    400

서울    apple     1950

          banana   2800

dtype: int64

 

그룹명에 접근하고 싶은 경우

df.groupby(['city''fruits'], as_index=False).apply(lambda d: d.name)

city      fruits 

부산     apple     (부산, apple)

          banana   (부산, banana)

          orange   (부산, orange)

서울     apple     (서울, apple)

           banana   (서울, banana)

dtype: object

 

apply 결과를 Series로 반환한 경우

・groupby로 작성한 label과 더해져 apply 함수 결과 index가 결과 전체의 row index가 됨.
・전체 행수는 결과에 따라 다름.
・as_index=False를 지정하여 index를 삭제 가능
def total_series(d): return d.price * d.quantity df.groupby(['city''fruits']).apply(total_series)

city      fruits 

city      fruits

부산     apple     0   100

          banana   2   750

                       3   1200

           orange    1   400

서울     apple      4    750

                        5   1200

           banana    6   2800

dtype: int64

 

allpy 결과에 row index를 지정하여 DataFrame으로 반환한 경우.

・apply 결과를 연결한 DataFrame을 작성 가능.
・groupby에 사용한 label은 index가 되지 않음.
・as_index=False 사용 불가.
def total_keepindex(d): 
           return pd.DataFrame({
                     'total': d.price * d.quantity # 여기서 반환된 DataFrame row index와 d의 row index는 같음 
})
df.groupby(['city''fruits']).apply(total_keepindex)

 

   total
 0  100
 1  400
 2  750
 3  1200
 4  750
 5  1200
 6  2800

 

allpy 결과에 row index를 지정 안하고 DataFrame으로 반환한 경우.

・groupby에 사용한 label이 index가 됨.
・as_index=False 사용 가능.
def total_keepnoindex(d): 
               return pd.DataFrame({ 
                     'total': (d.price * d.quantity).sum()
               }, index=['hoge'])
df.groupby(['city''fruits']).apply(total_keepnoindex)

 

       total
 city  fruits    
 부산  apple  hoge  100
   banana  hoge  1950
   orange  hoge  400
 서울  apple  hoge  1950
   banana  hoge  2800

 

allpy 함수 사용시 주의점

데이터 레코드 행수가 하나도 없는 DataFrame의 경우 apply 결과에 컬럼이 작성되지 않습니다.

먼저 데이터가 있는 경우를 보겠습니다.

pd.DataFrame({'hoge': [1,1,3], 'fuga': [10, 20, 30]}).groupby('hoge').apply(np.sum)

 

   hoge  fuga
 hoge    
 1  2  30
 3  3  

 

이번에는 DataFrame에 데이터가 없는 경우를 보겠습니다.

pd.DataFrame({'hoge': [], 'fuga': []}).groupby('hoge').apply(np.sum)

 

hoge
 


'fuga' 컬럼이 안 만들어졌습니다.

apply를 사용하여 DataFrame을 처리를 하는 경우에 데이터가 존재하는지 확인을 먼저 해주는 것이 좋을거 같습니다.

안 그러면 apply 실행 후 값을 취득하려고 할 때 해당 컬럼명이 존재하지 않아 예상치 못한 에러가 발생할 수도 있습니다.

 

출처 : https://ponyozzang.tistory.com/291

댓글