[Python pandas] 연속형을 범주형으로 변환하는 np.digitize(), pd.cut() 비교 (comparison of categorization using np.digitize(), pd.cut())
Python 분석과 프로그래밍/Python 데이터 전처리 2020. 2. 18. 17:19이번 포스팅에서는 연속형 변수를 여러개의 구간별로 구분하여 범주형 변수로 변환(categorization of a continuous variable by multiple bins) 하는 두가지 방법을 비교하여 설명하겠습니다.
(1) np.digitize(X, bins) 를 이용한 연속형 변수의 여러개 구간별 범주화
(2) pd.cut(X, bins, labels) 를 이용한 연속형 변수의 여러개 구간별 범주화
np.digitize(X, bins)와 pd.cut(X, bins, labels) 함수가 서로 비슷하면서도 사용법에 있어서는 모든 면에서 조금씩 다르므로 각 함수의 syntax에 맞게 정확하게 확인하고서 사용하기 바랍니다.
[ np.digitize()와 pd.cut() 비교 ]
구분 |
np.digitize(X, bins) |
pd.cut(X, bins, labels) |
bins=[start, end] |
[포함, 미포함) |
(미포함, 포함) |
bin 구간 대비 작거나 큰 수 |
bin 첫 구간 보다 작으면 [-inf, start) --> 자동으로 '1'로 digitize bin 마지막 구간 보다 크면 [end, inf) --> 자동으로 bin 순서에 따라 digitize |
bin 첫번째 구간보다 작으면 --> NaN bin 마지막 구간보다 크면 --> Nan |
label |
0, 1, 2, ... 순서의 양의 정수 자동 설정 |
사용자 지정 가능 (labels option) |
반환 (return) |
numpy array |
a list of categories with labels |
(1) np.digitize(X, bins) 를 이용한 연속형 변수의 여러개 구간별 범주화 |
먼저 예제로 사용할 간단한 pandas DataFrame을 만들어보겠습니다.
import pandas as pd import numpy as np df = pd.DataFrame({'col': np.arange(10)}) df
|
이제 np.digitize(X, bins=[0, 5, 8]) 함수를 사용해서 {[0, 5), [5, 8), [8, inf)} 구간 bin 별로 {1, 2, 3} 의 순서로 양의 정수를 자동으로 이름을 부여하여 'grp_digitize'라는 이름의 새로운 칼럼을 df DataFrame에 만들어보겠습니다.
참고로 '(' 또는 ')'는 미포함 (not included), '[' 또는 ']' 보호는 포함(included)을 나타냅니다.
bins=[0, 5, 8] # returns numpy array np.digitize(df['col'], bins)
df['grp_digitize'] = np.digitize(df['col'], bins) df [Out]:
|
(2) pd.cut(X, bins, labels) 를 이용한 연속형 변수의 여러개 구간별 범주화 |
이번에는 pd.cut(X, bins=[0, 5, 8]) 을 이용하여 {(0, 5], (5, 8]} 의 2개 구간별로 범주화해보겠습니다. array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) 의 각 원소가 어느 bin에 속하는지를 나타내는 category 리스트를 반환합니다.
import pandas as pd import numpy as np df = pd.DataFrame({'col': np.arange(10)}) # pd.cut(미포함, 포함] bins=[0, 5, 8] # returns a list of catogiries with labels pd.cut(df["col"], bins=bins)
|
위 (1)번의 np.digitize() 가 [포함, 미포함) 인 반면에 pd.cut()은 (미포함, 포함]으로 정반대입니다.
위 (1)번의 np.digitize() 가 bin 안의 처음 숫자보다 작거나 같은 값에 자동으로 '1'의 정수를 부여하고, bin 안의 마지막 숫자보다 큰 값에 대해서는 bin 순서에 따라 자동으로 digitze 정수를 부여하는 반면에, pd.cut()은 bin 구간에 없는 값에 대해서는 'NaN'을 반환하고 bin 구간 내 값에 대해서는 사용자가 labels=['a', 'b'] 처럼 입력해준 label 값을 부여해줍니다.
df['grp_cut'] = pd.cut(df["col"], bins=bins, labels=['a', 'b']) df [Out]:
|
이렇게 연속형 변수를 범주형 변수로 변환을 한 후에 'col' 변수에 대해 groupby('grp_cut') 로 그룹별 합계(sum by group)를 집계해 보겠습니다.
df.groupby('grp_cut')['col'].sum() [Out]: grp_cut
a 15
b 21
Name: col, dtype: int64 |
'grp_cut' 기준 그룹('a', 'b')별로 합(sum), 개수(count), 평균(mean), 분산(variance) 등의 여러개 통계량을 한번에 구하려면 사용자 정의 함수를 정의한 후에 --> df.groupby('grp_cut').apply(my_summary) 처럼 apply() 를 사용하면 됩니다. 그룹별로 통계량을 한눈에 보기에 좋도록 unstack()을 사용해서 세로로 길게 늘어선 결과를 가로로 펼쳐서 제시해보았습니다.
# UDF of summary statistics def my_summary(x): result = { 'sum': x.sum(), 'count': x.count(), 'mean': x.mean(), 'variance': x.var() } return result df.groupby('grp_cut')['col'].apply(my_summary).unstack() [Out]:
|
많은 도움이 되었기를 바랍니다.
이번 포스팅이 도움이 되었다면 아래의 '공감~'를 꾹 눌러주세요. :-)