[Python pandas] 여러개의 칼럼에 대해 다른 함수를 적용한 Group By 집계: grouped.apply(functions)
Python 분석과 프로그래밍/Python 데이터 전처리 2018. 9. 6. 22:48지난번 포스팅에서는 Python pandas에서 Group By 집계 시에 grouped.agg()안에 칼럼과 함수를 매핑한 Dict를 사용하여 칼럼별로 특정 GroupBy 집계 함수를 적용하는 방법을 소개하였습니다.
이번 포스팅에서는 Python pandas에서 Group By 집계 시에 grouped.apply()를 사용하여 여러개의 칼럼(Multiple Columns)에 대해서 각기 다른 함수들을 적용하는 방법을 소개하겠습니다. 지난번 포스팅과 비교를 해보시고, 편리하거나 이해하기 쉽다고 느껴지는 방법을 사용하면 되겠습니다.
(1) 데이터프레임에서 여러개의 칼럼에 대해 다른 함수 적용하여 Group By 집계하기
: grouped.apply(function)
(2) 계층적 인덱스를 가진 데이터프레임의 여러개의 칼럼에 대해 다른 함수 적용하여 Group By 집계하기
: grouped(level=['index1', 'index2']).apply(function)
(1) 데이터프레임에서 여러개의 칼럼에 대해 다른 함수 적용하여 Group By 집계하기 : grouped.apply(function) |
예제로 사용할 간단한 데이터프레임을 만들어보겠습니다.
import numpy as np import pandas as pd df = pd.DataFrame({'grp_col_1' : ['a', 'a', 'a', 'a', 'a', 'b', 'b', 'b', 'b', 'b'], 'grp_col_2' : ['c', 'c', 'd', 'd', 'd', 'e', 'e', 'f', 'f', 'f'], 'val_1' : np.arange(10), 'val_2' : np.random.randn(10)})
df
|
위에서 만든 데이터프레임의 'val_1' 칼럼에 대해서 평균(mean)과 표준편차(std)를 구하고, 'val_2' 칼럼에 대해서는 최대값(max)과 최소값(min), 그리고 범위(range)를 구하는 사용자 정의 함수 func()를 정의해보겠습니다. 처음에 빈 Dict 를 선언하고, 각 칼럼별 함수의 이름(key)과 함수를 적용한 결과(value)를 Dict의 key와 value로 매핑한 후에, 마지막에 pandas Series 로 반환하는 사용자 정의 함수입니다.
def func(x): d = {} d['val_1_mean'] = x['val_1'].mean() d['val_1_std'] = x['val_1'].std() d['val_2_max'] = x['val_2'].max() d['val_2_min'] = x['val_2'].min() d['val_2_range'] = x['val_2'].max() - x['val_2'].min() return pd.Series(d, index=['val_1_mean', 'val_1_std', 'val_2_max', 'val_2_min', 'val_2_range'])
|
위에서 정의한 사용자 정의 함수 func()를 Group By 집계 시 grouped.apply(func) 처럼 apply() 괄호 안에 함수이름을 써주면 됩니다. Group By 집계에 'grp_col_1', 'grp_col_2'의 두개 변수를 사용하였으므로 아래의 결과처럼 계층이 있는 인덱스(Hierarchical Index)를 가진 데이터프레임이 반환되었습니다.
df_return = df.groupby(['grp_col_1', 'grp_col_2']).apply(func) df_return
|
계층적 인덱스를 사용하고 싶지 않다면 reset_index() 로 인덱스를 칼럼으로 변환해주면 됩니다.
df_return.reset_index()
|
계층적 인덱스 전부 말고 일부만 선별해서 칼럼으로 변환을 하고 싶으면 reset_index(level='index_name') 처럼 reset_index() 의 안에 level 을 지정해주면 됩니다.
df_return.reset_index(level='grp_col_2')
|
계층적 인덱스를 아예 삭제하고 싶으면 reset_index(drop=True) 처럼 drop=True 를 추가해주면 됩니다. (물론, 이렇게하면 Group By가 무엇을 기준으로 되었는지 파악이 불가능하기 때문에 사용하면 안될거 같긴 합니다. ^^;;;)
df_return.reset_index(drop=True)
|
Group By로 집계되어 반환된 객체가 데이터프레임으로 특정 칼럼만 선택할 수 있습니다. 예를 들어, 'val_1_mean', 'val_1_std'의 두 개 칼럼만 선택해보면 아래와 같습니다.
df_return[['val_1_mean', 'val_1_std']]
|
(2) 계층적 인덱스를 가진 데이터프레임의 여러개의 칼럼에 대해 다른 함수 적용하여 Group By 집계하기 : grouped(level=['index1', 'index2']).apply(function) |
위의 (1)번 예에서 들었던 데이터프레임과 'val_1', 'val_2' 의 숫자형 변수와 값은 동일하며, Group By 집계를 하는 기준이 되는 'grp_col_1', 'grp_col_2' 변수는 'grp_idx_1', 'grp_idx_2' 라는 이름의 인덱스 이름으로 하여 계층적 인덱스로 하여 데이터프레임을 만들어보겠습니다.
pd.MultiIndex.from_arrays() 를 사용하여 계층적 인덱스를 만들어줍니다. (R이나 SQL을 사용하다가 Python 의 계층적 인덱스를 처음 보면 '이게 뭐지?' 싶었는데요, 자꾸 써보니 나름 편리합니다)
pd.DataFrame() 으로 데이터프레임을 만들 때 index 에 pd.MultiIndex.from_arrays() 로 만든 인덱스를 할당해주면 됩니다.
# How to make a DataFrame with Hierarchical Index arrays = [['a', 'a', 'a', 'a', 'a', 'b', 'b', 'b', 'b', 'b'], ['c', 'c', 'd', 'd', 'd', 'e', 'e', 'f', 'f', 'f']] myindex = pd.MultiIndex.from_arrays(arrays, names=('grp_idx_1', 'grp_idx_2'))
df2 = pd.DataFrame({'val_1': np.arange(10), 'val_2': np.random.randn(10)}, index = myindex) df2
|
계층적 인덱스를 가진 데이터프레임에 대해 Group By 집계를 할 때는 groupby(level=['index_1', 'index_2']).apply(function) 의 형태로 지정을 해주면 됩니다. groupby() 로 집계 기준을 설정하고 apply(function)으로 함수를 지정해주는 것은 위의 (1)번과 같은데요, groupby()의 안에 level=['index_1', 'index_2'] 처럼 입력하는 부분이 다릅니다.
df2.groupby(level=['grp_idx_1', 'grp_idx_2']).apply(func)
|
많은 도움이 되었기를 바랍니다.