[Python Pandas] 동일 길이로 나누어서 범주 만들기 pd.cut(), 동일 개수로 나누어서 범주 만들기 pd.qcut()
Python 분석과 프로그래밍/Python 데이터 전처리 2018. 12. 23. 00:04이번 포스팅에서는 groupby() 를 사용할 때
(1) pd.cut()으로 동일 길이로 나누어서 범주를 만든 후 GroupBy()로 그룹별 통계량 구하기
(2) pd.qcut()으로 동일 개수로 나누어서 범주를 만든 후 GroupBy()로 그룹별 통계량 구하기
를 해보겠습니다.
먼저, 예제로 사용할 간단한 DataFrame을 만들어보겠습니다.
import numpy as np import pandas as pd from pandas import DataFrame np.random.seed(123) df = DataFrame({'col_1': np.random.randint(20, size=20), 'col_2': np.random.randn(20)}) df
|
(1) pd.cut : 동일 길이로 나누어서 범주 만들기(equal-length buckets categorization) |
'col_1' 칼럼에 대해서 4개의 동일한 길이로 범주를 만들어보겠습니다.
카테고리의 구간이 [(-0.019, 4.75] < (4.75, 9.5] < (9.5, 14.25] < (14.25, 19.0]] 로서 4개의 각 구간의 길이가 동일함을 알 수 있습니다.
factor_col_1 = pd.cut(df.col_1, 4) factor_col_1 0 (9.5, 14.25] 1 (-0.019, 4.75]
2 (-0.019, 4.75]
3 (4.75, 9.5]
4 (14.25, 19.0]
5 (14.25, 19.0]
6 (9.5, 14.25]
7 (-0.019, 4.75]
8 (-0.019, 4.75]
9 (14.25, 19.0]
10 (14.25, 19.0]
11 (4.75, 9.5]
12 (-0.019, 4.75]
13 (9.5, 14.25]
14 (-0.019, 4.75]
15 (14.25, 19.0]
16 (14.25, 19.0]
17 (9.5, 14.25]
18 (-0.019, 4.75]
19 (-0.019, 4.75]
Name: col_1, dtype: category
Categories (4, interval[float64]): [(-0.019, 4.75] < (4.75, 9.5] < (9.5, 14.25] < (14.25, 19.0]]
|
이제 'factor_col_1'이라는 'col_1' 칼럼에 대한 4개 구간의 범주를 GroupBy() 에 넣어서 각 범주의 그룹별로 agg() 함수로 개수(count), 평균(mean), 표준편차(std), 최소값(min), 최대값(max) 값을 계산해보겠습니다.
grouped_col_1 = df.col_1.groupby(factor_col_1) grouped_col_1.agg(['count', 'mean', 'std', 'min', 'max'])
|
위와 동일한 결과를 아래 처럼 통계집계를 하는 사용자정의함수와 apply() 를 사용해서 구할 수도 있습니다.
def summary_func(group): return {'count': group.count(), 'mean': group.mean(), 'std': group.std(), 'min': group.min(), 'max': group.max()} grouped_col_1.apply(summary_func) col_1
(-0.019, 4.75] count 8.000000
max 4.000000
mean 1.125000
min 0.000000
std 1.457738
(4.75, 9.5] count 2.000000
max 9.000000
mean 7.500000
min 6.000000
std 2.121320
(9.5, 14.25] count 4.000000
max 14.000000
mean 12.750000
min 10.000000
std 1.892969
(14.25, 19.0] count 6.000000
max 19.000000
mean 17.000000
min 15.000000
std 1.788854
Name: col_1, dtype: float64 |
위의 결과를 좀더 보기에 좋도록 unstack()를 사용해서 길게(long) 제시된 결과를 옆으로 넓게(wide) 표형식으로 만들어보겠습니다.
grouped_col_1.apply(summary_func).unstack()
|
위의 결과의 'count' 개수 부분을 보면 각 범주 구간 [(-0.019, 4.75] < (4.75, 9.5] < (9.5, 14.25] < (14.25, 19.0]] 그룹 별로 개수가 8개, 2개, 4개, 6개로서 각각 다릅니다. 이는 랜덤 숫자에 대해서 구간별 길이를 동일하게 했기 때문에 구간 그룹별 개수가 다르게 된 것입니다.
그러면, 다음으로 구간별 '동일한 개수(equal-size)'로 범주 바구니(bucket categorization)를 만들어보겠습니다.
(2) pd.qcut() : 동일 개수로 나누어서 범주 만들기 (equal-size buckets categorization) |
pd.qcut() 함수를 사용하여 'col_2'에 대해서 각 범주 바구니별로 동일하게 4개의 개수를 가지도록 범주를 만들어보겠습니다. 이때 labels=False 로 설정하여 label이 0, 1, 2, 3 이런 식으로 0부터 순차적으로 1씩 증가하게 하였습니다.
bucket_qcut_col_2 = pd.qcut(df.col_2, 4, labels=False) bucket_qcut_col_2 0 3
1 3
2 0
3 2
4 1
5 3
6 2
7 0
8 1
9 3
10 3
11 0
12 0
13 1
14 1
15 1
16 2
17 2
18 0
19 2
Name: col_2, dtype: int64 |
아래처럼 labels=np.arange(4, 0, -1)로 직접 지정을 해주면 label이 4, 3, 2, 1 이런식으로 4부터 1씩 줄어드는 순서로 할당이 됩니다. 위의 label 과 정 반대로 할당이 되었습니다.
bucket_qcut_label_col_2 = pd.qcut(df.col_2, 4, labels=np.arange(4, 0, -1)) bucket_qcut_label_col_2 0 1
1 1
2 4
3 2
4 3
5 1
6 2
7 4
8 3
9 1
10 1
11 4
12 4
13 3
14 3
15 3
16 2
17 2
18 4
19 2 Name: col_2, dtype: category
Categories (4, int64): [4 < 3 < 2 < 1] |
그럼 [4 < 3 < 2 < 1] 순서로 동일 개수로 나눈 4개의 그룹별 통계량을 계산해보겠습니다.
grouped = df.col_2.groupby(bucket_qcut_label_col_2) grouped.apply(summary_func).unstack()
|
'count' 개수가 4개의 각 그룹별로 모두 '5'로서 동일한 것을 알 수 있습니다.
많은 도움이 되었기를 바랍니다.
이번 포스팅이 도움이 되었다면 아래의 '공감~'를 꾹 눌러주세요. :-)