[Python] 연속형 변수의 이산형화(discretization) : np.digitize(data, bins), pd.get_dummies(), np.where(condition, 'factor1', 'factor2', ...)
Python 분석과 프로그래밍/Python 데이터 전처리 2016. 12. 20. 23:33지난번 포스팅에서는
- Python sklearn.preprocessing.Binarizer()를 이용한 연속형 변수의 이항변수화(binarization)
- Python sklearn.preprocessing.OneHotEncoder()를 이용한 범주형 변수의 이항변수화
에 대해서 알아보았습니다.
이번 포스팅에서는 Python np.digitize(), np.where() 를 이용한 연속형 변수의 이산형화(discretization)에 대해서 알아보겠습니다.
이항변수화(binarization)는 '0'과 '1'의 값만을 가지는 가변수(dummy variable)를 만드는 것을 의미하며, 이에 비해 이산형화(discretization)은 연속형 변수를 2개 이상의 범주(category)를 가지는 변수로 변환해주는 것을 말합니다.
먼저, 필요한 모듈을 불러오고, 예제로 사용할 DataFrame을 만들어보겠습니다.
#%% discretization of continuous data, binning data
# importing modules In [1]: import numpy as np In [2]: import pandas as pd In [3]: from pandas import DataFrame
# setting random seed number In [4]: np.random.seed(10)
In [5]: df = DataFrame({'C1': np.random.randn(20), ...: 'C2': ['a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', ...: 'b', 'b', 'b', 'b', 'b', 'b', 'b', 'b', 'b', 'b']}) ...: In [6]: df Out[6]: C1 C2
|
(1) np.digitize(data, bins)를 이용한 연속형 변수의 이산형화 (discretization) |
연속형 변수 'C1'을 최소~최대값 구간을 10개 bin으로 균등하게 나누어서 'C1_bin'이라는 이름의 칼럼으로 이산형화 변환해보겠습니다. ifelse 등의 조건문을 길게 안써도 np.linspace()와 np.dititize() 를 사용해서 아주 간단하게 이산형화 할 수 있습니다.
# making 10 bins, from min to max of 'C1' column In [7]: bins = np.linspace(df.C1.min(), df.C1.max(), 10) In [8]: bins Out[8]: array([-1.54540029, -1.20874059, -0.87208089, -0.53542119, -0.19876149, 0.1378982 , 0.4745579 , 0.8112176 , 1.1478773 , 1.484537 ])
# making digitized column using np.digitize(data, bins) In [9]: df['C1_bin'] = np.digitize(df['C1'], bins) In [10]: df Out[10]: C1 C2 C1_bin
|
연속형 변수를 이산형화 해서 어디에 써먹나 싶을텐데요, 간단한 예를 들자면 이산형화한 범주(혹은 요인)별로 요약통계량을 집계한다든지, 범주 간 평균 차이나 독립성을 검정한다든지, 분류모형의 목표변수로 사용한다든지, indexing 하는데 사용한다든지 ... 등이 있을 수 있겠네요.
# aggregation with groupby() In [11]: df.groupby('C1_bin')['C1'].size() Out[11]: C1_bin
# mean by 'C1_bin' groups In [12]: df.groupby('C1_bin')['C1'].mean() Out[12]: C1_bin
# standard deviation by 'C1_bin' groups In [13]: df.groupby('C1_bin')['C1'].std() Out[13]: C1_bin
# value counts by 'C1_bin' groups In [14]: df.groupby('C1_bin')['C2'].value_counts() Out[14]: C1_bin C2
# indexing In [15]: df_bin2 = df[df['C1_bin'] == 2] In [16]: df_bin2 Out[16]: C1 C2 C1_bin |
(2) pd.get_dummies() 를 이용해 가변수(dummy var) 만들기 |
위에서 새로 만든 범주형 변수 'C1_bin'과 pd.get_dummies() 함수를 사용해서 가변수(dummy variable)을 만들어보겠습니다.
prefix 옵션을 사용하면 가변수에 공통으로 접두사를 추가할 수 있습니다.
drop_first=True 옵션을 설정하면 가변수의 첫번째 변수를 자동으로 삭제를 해주며, 가변수 함정(dummy trap)을 피할 수 있게 해줍니다.
# get dummy variables with prefix from a categorical variable
In [17]: pd.get_dummies(df['C1_bin'], prefix='C1') Out[17]: C1_1 C1_2 C1_3 C1_5 C1_6 C1_7 C1_8 C1_9 C1_10
# drop_first : Whether to get k-1 dummies out of k categorical levels In [18]: pd.get_dummies(df['C1_bin'], prefix='C1', drop_first=True) Out[18]: C1_2 C1_3 C1_5 C1_6 C1_7 C1_8 C1_9 C1_10
|
(3) np.where(condition, factor1, factor2, ...)를 이용한 연속형 변수의 이산형화 |
np.where() 를 사용하면 조건절에 좀더 유연하게 조건을 부여해서 이산형화, 범주화를 할 수 있습니다. 연속형 변수 'C1'의 '평균'을 기준으로 평균 이상으로 'high', 평균 미만이면 'low'로 이산형화 변수 'high_low' 신규 변수를 만들어본 후에, 'high_low' 이산형화 변수를 기준으로 요약통계량을 계산해보겠습니다.
# discretization using np.where(condition, factor1, factor2, ...) In [17]: df['high_low'] = np.where(df['C1'] >= df.C1.mean(), 'high', 'low') In [18]: df Out[18]: C1 C2 C1_bin high_low In [19]: df.groupby('high_low')['C1'].size() Out[19]: high_low high 11 low 9 dtype: int64 In [20]: df.groupby('high_low')['C1'].mean() Out[20]: high_low high 0.717408 low -0.613011 Name: C1, dtype: float64 In [21]: df.groupby('high_low')['C1'].std() Out[21]: high_low high 0.473769 low 0.607895 Name: C1, dtype: float64
|
np.where(condition, ...) 에서 조건절을 조금 더 복잡하게 해서 'Q1(quantile 1, 25%)', 'Q3(quantile 3, 75%) 를 기준으로 '01_high', '02_medium', '03_low' 로 구분해서 이산형화 변환을 해보겠습니다.
괄호 안에 조건절 주는 부분이 조금 복잡하므로 주의하시기 바랍니다.
# calculating Q1, Q3 In [22]: Q1 = np.percentile(df['C1'], 25) In [23]: Q1 Out[23]: -0.31097154812443017 In [24]: Q3 = np.percentile(df['C1'], 75) In [25]: Q3 Out[25]: 0.64482172401746174
In [26]: df['h_m_l'] = np.where(df['C1'] >= Q3, '01_high', ...: np.where(df['C1'] >= Q1, '02_medium', '03_low')) ...: In [27]: df Out[27]: C1 C2 C1_bin high_low h_m_l
|
3개의 범주로 구분해서 새로 만든 'h_m_l' 이산형화 변환 변수를 기준으로 요약통계량을 계산해보면 아래와 같습니다.
In [28]: df.groupby('h_m_l')['C1'].size() Out[28]: h_m_l dtype: int64 In [29]: df.groupby('h_m_l')['C1'].mean() Out[29]: h_m_l Name: C1, dtype: float64 In [30]: df.groupby('h_m_l')['C1'].std() Out[30]: h_m_l Name: C1, dtype: float64
|
이상으로 이산형화(discretization) 변환에 대해서 마치도록 하겠습니다.
다음번 포스팅에서는 다항 차수 변환(polynomial variables transformation)에 대해서 알아보겠습니다.
많은 도움 되었기를 바랍니다.