02-11. 그룹화 계산 (groupby)
DataFrame.groupby(by=None, axis=0, level=None, as_index=True, sort=True, group_keys=True, squeeze=NoDefault.no_default, observed=False, dropna=True)
개요
groupby 메서드는 데이터를 그룹화하여 연산을 수행하는 메서드 입니다.
사용법
기본 사용법
※ 자세한 내용은 아래 예시를 참고 바랍니다.
df.groupby(by=None, axis=0, level=None, as_index=True, sort=True, group_keys=True, squeeze=NoDefault.no_default, observed=False, dropna=True)
by : 그룹화할 내용입니다. 함수, 축, 리스트 등등이 올 수 있습니다.
axis : 그룹화를 적용할 축입니다.
level : 멀티 인덱스의 경우 레벨을 지정할 수 있습니다.
as_index : 그룹화할 내용을 인덱스로 할지 여부입니다. False이면 기존 인덱스가 유지됩니다.
sort : 그룹키를 정렬할지 여부입니다.
group_keys : apply메서드 사용시 결과에따라 그룹화 대상인 열이 인덱스와 중복(group key)이 될 수 있습니다. 이 때, group_keys=False로 인덱스를 기본값으로 지정할 수 있습니다.
squeeze : 결과가 1행 or 1열짜리 데이터일 경우 Series로, 1행&1열 짜리 데이터일 경우 스칼라로 출력합니다.
observed : Categorical로 그룹화 할 경우 Categorical 그룹퍼에 의해 관찰된 값만 표시할 지 여부입니다.
dropna : 결측값을 계산에서 제외할지 여부입니다.
예시
먼저 기본적인 사용법 예시를위하여 데이터를 만들어 보겠습니다.
idx=['A','A','B','B','B','C','C','C','D','D','D','D','E','E','E']
col=['col1','col2','col3']
data = np.random.randint(0,9,(15,3))
df = pd.DataFrame(data=data, index=idx, columns=col).reset_index()
print(df)
>>
index col1 col2 col3
0 A 5 0 7
1 A 2 6 2
2 B 1 1 8
3 B 1 6 6
4 B 3 2 3
5 C 1 0 8
6 C 8 4 1
7 C 1 5 5
8 D 3 3 7
9 D 5 7 7
10 D 1 6 5
11 D 4 0 0
12 E 0 5 6
13 E 2 7 7
14 E 0 7 0
기본적인 사용법
추가 메서드 없이 groupby 메서드를 실행하면 DataFrameGroupBy 오브젝트가 생성이 됩니다.
print(df.groupby('index')) # index 컬럼에 대해서 groupby 수행
여기에 추가 연산 메서드를 입력하면, 해당 열의 그룹화된 데이터에 대해서 연산이 수행됩니다.
print(df.groupby('index').mean())
>>
col1 col2 col3
index
A 3.500000 3.000000 4.500000
B 1.666667 3.000000 5.666667
C 3.333333 3.000000 4.666667
D 3.250000 4.000000 4.750000
E 0.666667 6.333333 4.333333
추가 메서드의 적용
추가 메서드로는 단순 연산 메서드가 아닌 agg나 apply 메서드 등 여러 메서드의 적용이 가능합니다.
print(df.groupby('index').count())
>>
col1 col2 col3
index
A 2 2 2
B 3 3 3
C 3 3 3
D 4 4 4
E 3 3 3
agg메서드를 이용해 여러 연산을 수행할 경우 MultiColumns 형태로 출력됩니다.
print(df.groupby('index').agg(['sum','mean']))
>>
col1 col2 col3
sum mean sum mean sum mean
index
A 7 3.500000 6 3.000000 9 4.500000
B 5 1.666667 9 3.000000 17 5.666667
C 10 3.333333 9 3.000000 14 4.666667
D 13 3.250000 16 4.000000 19 4.750000
E 2 0.666667 19 6.333333 13 4.333333
group_keys 인수의 사용
apply 메서드를 이용해 groupby연산을 수행할 경우, groupkey가 설정되기 때문에 때에따라 컬럼과 인덱스가 중복될 수 있습니다. 이 때 group_keys=False를 통해 기본 인덱스로 출력이 가능합니다.
def top (df,n=2,col='col1'):
return df.sort_values(by=col)[-n:] #상위 n개 열을 반환하는 함수 top 생성
print(df.groupby('index').apply(top))
>>
index col1 col2 col3 # 인덱스와 index열이 중복
index
A 1 A 2 6 2
0 A 5 0 7
B 3 B 1 6 6
4 B 3 2 3
C 7 C 1 5 5
6 C 8 4 1
D 11 D 4 0 0
9 D 5 7 7
E 14 E 0 7 0
13 E 2 7 7
print(df.groupby('index',group_keys=False).apply(top))
>>
index col1 col2 col3 # 인덱스와의 중복이 제거
1 A 2 6 2
0 A 5 0 7
3 B 1 6 6
4 B 3 2 3
7 C 1 5 5
6 C 8 4 1
11 D 4 0 0
9 D 5 7 7
14 E 0 7 0
13 E 2 7 7
observed 인수의 사용
Categorical 객체를 생성할 때, 그룹화(groupby)할 열에 있는 값이 아닌 값을 포함하게되면, 그룹화 할 때 해당 값을 표시할지 여부를 선택할 수 있습니다.
df_cat = pd.Categorical(df['index'], categories=['A','B','C','D','E','F']) # df의 index열에 대해서 A,B,C,D,E,F 로 Categorical을 하여 df_cat 생성
print(df_cat)
>>
['A', 'A', 'B', 'B', 'B', ..., 'D', 'D', 'E', 'E', 'E']
Length: 15
Categories (6, object): ['A', 'B', 'C', 'D', 'E', 'F'] # 값은 A~E 까지 있지만, 카테고리는 F까지 지정함.
위 catrory 객체에 대해서 col1열을 groupby 하면 아래와 같이 카테고리에만 존재하는 F에대한 groupby 값이 출력됩니다.
print(df['col1'].groupby(df_cat).count())
>>
A 2
B 3
C 3
D 4
E 3
F 0 # index열에는 없지만, F까지 category 되었음. observed=False(기본값)인 경우 카테고리 전체가 표시됨.
Name: col1, dtype: int64
observed=True로 할경우 관찰되지 않는값 (카테고리에만 존재하는값)은 표시되지 않습니다.
print(df['col1'].groupby(df_cat,observed=True).count())
>>
A 2
B 3
C 3
D 4
E 3
Name: col1, dtype: int64
as_index인수의 사용
특정 열을 지정하여 groupby할 경우 해당 열이 인덱스가 되는데, as_index=False로 하여 기존 인덱스의 유지가 가능합니다.
print(df.groupby(['index'],as_index=False).sum())
>>
index col1 col2 col3
0 A 7 6 9
1 B 5 9 17
2 C 10 9 14
3 D 13 16 19
4 E 2 19 13
dropna인수의 사용
dropna인수를 통해 결측값(NaN)이 포함된 경우 그룹화에서 제외할지 여부를 정할 수 있습니다.
먼저 index열의 6번행을 결측값(NaN)으로 변경해보겠습니다.
df.loc[6,'index'] = np.NaN
print(df)
>>
index col1 col2 col3
0 A 5 0 7
1 A 2 6 2
2 B 1 1 8
3 B 1 6 6
4 B 3 2 3
5 C 1 0 8
6 NaN 8 4 1
7 C 1 5 5
8 D 3 3 7
9 D 5 7 7
10 D 1 6 5
11 D 4 0 0
12 E 0 5 6
13 E 2 7 7
14 E 0 7 0
일반적인 사용시 NaN은 계산에서 제외되어 인덱스에 표시되지 않은것을 확인할 수 있습니다.
print(df.groupby('index').sum())
>>
col1 col2 col3
index
A 7 6 9
B 5 9 17
C 2 5 13
D 13 16 19
E 2 19 13
dropna=False인 경우 인덱스에 NaN이 포함되어 계산된 것을 알 수 있습니다.
print(df.groupby('index',dropna=False).sum())
>>
col1 col2 col3
index
A 7 6 9
B 5 9 17
C 2 5 13
D 13 16 19
E 2 19 13
NaN 8 4 1 # NaN이 표시됩니다.
level인수의 사용 (Multi Index)
Multi Index의 경우 level을 숫자나 str 형태로 지정해주어 groupby를 실행할 수 있습니다.
먼저 Multi Index 객체를 생성해보겠습니다.
idx = [['idx1','idx1','idx2','idx2','idx2'],['row1','row2','row1','row2','row3']]
col = ['col1','col2','col2']
data = np.random.randint(0,9,(5,3))
df = pd.DataFrame(data=data, index = idx, columns = col).rename_axis(index=['lv0','lv1'])
print(df)
>>
col1 col2 col2
lv0 lv1
idx1 row1 7 3 7
row2 2 1 6
idx2 row1 1 7 2
row2 3 5 7
row3 5 1 8
level을 int로 지정해주는 경우
print(df.groupby(level=1).sum())
>>
col1 col2 col2
lv1
row1 8 10 9
row2 5 6 13
row3 5 1 8
level을 str로 지정해주는경우 + (여러개 지정시 순차적으로 groupby 됩니다.)
print(df.groupby(['lv1','lv0']).sum())
>>
col1 col2 col2
lv1 lv0
row1 idx1 7 3 7
idx2 1 7 2
row2 idx1 2 1 6
idx2 3 5 7
row3 idx2 5 1 8
'파이썬완전정복-Pandas DataFrame > 02. 객체내 연산' 카테고리의 다른 글
Pandas DataFrame 02-12. 지수가중함수 (ewm) (0) | 2022.01.28 |
---|---|
Pandas DataFrame 02-10. 기간이동 계산 (rolling) (0) | 2022.01.17 |
Pandas DataFrame 02-09. 누적 계산 (expanding) (0) | 2022.01.11 |
Pandas DataFrame 02-08. 차이[백분률] (pct_change) (0) | 2022.01.09 |
Pandas DataFrame 02-07. 차이[이산] (diff) (0) | 2022.01.09 |