Pandas 그룹내에서 순서대로 인덱스 부여 - cumcount()
Contents
cumcount()
를 이용해서 그룹별로 각각 번호를 매길 수 있다.
1. 핵심 요약
- groupby() 한 거에
cumcount()
해서 그룹내에서 각각 순서대로 번호를 매길 수 있음 - 원래 DataFrame 모양 및 index 유지됨 (transformation)
df['per_group_index'] = df.groupby('class').cumcount() + 1
2. 사용 예시
import pandas as pd
df = pd.DataFrame({
'class': ['a', 'a', 'a', 'b', 'b', 'a'],
# 'class_temp': list('aaabba'), # 이렇게도 되네
})
df
class | |
---|---|
0 | a |
1 | a |
2 | a |
3 | b |
4 | b |
5 | a |
위와 같은 데이터가 있다고 하자.
# cumcount() 사용. 원래 index(0~5) 유지됨
df.groupby(['class']).cumcount()
0 0
1 1
2 2
3 0
4 1
5 3
dtype: int64
groupby 한 거에다 cumcount()
한 결과를 보면 Series가 나왔다. 원래 DataFrame의 index도 유지되어 있다.
# 1부터 번호 매기고 싶음
df.groupby(['class']).cumcount() + 1
0 1
1 2
2 3
3 1
4 2
5 4
dtype: int64
1부터 번호를 매기고 싶으니, 1을 더해주자.
# 실제로 df에 column 추가
df['per_group_index'] = df.groupby(['class']).cumcount() + 1
df
class | per_group_index | |
---|---|---|
0 | a | 1 |
1 | a | 2 |
2 | a | 3 |
3 | b | 1 |
4 | b | 2 |
5 | a | 4 |
확인해 본 코드로 실제 DataFrame에 per_group_index
column을 추가했다.
# 보기 좋게 소팅
df = df.sort_values(['class', 'per_group_index'])
df
class | per_group_index | |
---|---|---|
0 | a | 1 |
1 | a | 2 |
2 | a | 3 |
5 | a | 4 |
3 | b | 1 |
4 | b | 2 |
필요에 따라 소팅도 해주면 끝.
3. 기타
{Pandas 문서} DataFrameGroupBy.cumcount 따르면, 아래 코드와 비슷한 느낌 이라고 한다.
import numpy as np
df.groupby('class').apply(lambda x: pd.Series(np.arange(len(x)) + 1, index=x.index))
class
a 0 1
1 2
2 3
5 4
b 3 1
4 2
dtype: int32
결과 Series가 멀티인덱스라 인덱스가 달라져서 바로 대입은 안되는데, cumcount()
쓰면 되니까 그런가 부다 하자.
Reference
- {Stackoverflow} Add a sequential counter column on groups to a pandas dataframe
- {Pasdas 문서} Group by > Enumerate group items
- {Pandas 문서} DataFrameGroupBy.cumcount