지난번 포스팅에서는
- 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)
# making DataFrame with continuous values
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 0 1.331587 a 1 0.715279 a 2 -1.545400 a 3 -0.008384 a 4 0.621336 a 5 -0.720086 a 6 0.265512 a 7 0.108549 a 8 0.004291 a 9 -0.174600 a 10 0.433026 b 11 1.203037 b 12 -0.965066 b 13 1.028274 b 14 0.228630 b 15 0.445138 b 16 -1.136602 b 17 0.135137 b 18 1.484537 b 19 -1.079805 b
|
(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 0 1.331587 a 9 1 0.715279 a 7 2 -1.545400 a 1 3 -0.008384 a 5 4 0.621336 a 7 5 -0.720086 a 3 6 0.265512 a 6 7 0.108549 a 5 8 0.004291 a 5 9 -0.174600 a 5 10 0.433026 b 6 11 1.203037 b 9 12 -0.965066 b 2 13 1.028274 b 8 14 0.228630 b 6 15 0.445138 b 6 16 -1.136602 b 2 17 0.135137 b 5 18 1.484537 b 10 19 -1.079805 b 2
|
연속형 변수를 이산형화 해서 어디에 써먹나 싶을텐데요, 간단한 예를 들자면 이산형화한 범주(혹은 요인)별로 요약통계량을 집계한다든지, 범주 간 평균 차이나 독립성을 검정한다든지, 분류모형의 목표변수로 사용한다든지, indexing 하는데 사용한다든지 ... 등이 있을 수 있겠네요.
# aggregation with groupby()
In [11]: df.groupby('C1_bin')['C1'].size()
Out[11]:
C1_bin 1 1 2 3 3 1 5 5 6 4 7 2 8 1 9 2 10 1 dtype: int64
# mean by 'C1_bin' groups
In [12]: df.groupby('C1_bin')['C1'].mean()
Out[12]:
C1_bin 1 -1.545400 2 -1.060491 3 -0.720086 5 0.012999 6 0.343076 7 0.668307 8 1.028274 9 1.267312 10 1.484537 Name: C1, dtype: float64
# standard deviation by 'C1_bin' groups
In [13]: df.groupby('C1_bin')['C1'].std()
Out[13]:
C1_bin 1 NaN 2 0.087384 3 NaN 5 0.122243 6 0.111985 7 0.066428 8 NaN 9 0.090898 10 NaN Name: C1, dtype: float64
# value counts by 'C1_bin' groups
In [14]: df.groupby('C1_bin')['C2'].value_counts()
Out[14]:
C1_bin C2 1 a 1 2 b 3 3 a 1 5 a 4 b 1 6 b 3 a 1 7 a 2 8 b 1 9 a 1 b 1 10 b 1 Name: C2, dtype: int64
# indexing
In [15]: df_bin2 = df[df['C1_bin'] == 2]
In [16]: df_bin2
Out[16]:
C1 C2 C1_bin 12 -0.965066 b 2 16 -1.136602 b 2 19 -1.079805 b 2
|
(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 0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 1 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 2 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 3 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 4 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 5 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 6 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 7 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 8 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 9 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 10 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 11 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 12 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 13 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 14 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 15 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 16 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 17 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 18 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 19 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
# drop_first : Whether to get k-1 dummies out of k categorical levels # by removing the first level to avoid dummy trap
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 0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 1 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 2 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 3 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 4 0.0 0.0 0.0 0.0 1.0 0.0 0.0 0.0 5 0.0 1.0 0.0 0.0 0.0 0.0 0.0 0.0 6 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 7 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 8 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 9 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 10 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 11 0.0 0.0 0.0 0.0 0.0 0.0 1.0 0.0 12 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 13 0.0 0.0 0.0 0.0 0.0 1.0 0.0 0.0 14 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 15 0.0 0.0 0.0 1.0 0.0 0.0 0.0 0.0 16 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 17 0.0 0.0 1.0 0.0 0.0 0.0 0.0 0.0 18 0.0 0.0 0.0 0.0 0.0 0.0 0.0 1.0 19 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
|
(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 0 1.331587 a 9 high 1 0.715279 a 7 high 2 -1.545400 a 1 low 3 -0.008384 a 5 low 4 0.621336 a 7 high 5 -0.720086 a 3 low 6 0.265512 a 6 high 7 0.108549 a 5 low 8 0.004291 a 5 low 9 -0.174600 a 5 low 10 0.433026 b 6 high 11 1.203037 b 9 high 12 -0.965066 b 2 low 13 1.028274 b 8 high 14 0.228630 b 6 high 15 0.445138 b 6 high 16 -1.136602 b 2 low 17 0.135137 b 5 high 18 1.484537 b 10 high 19 -1.079805 b 2 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
# discretizing 3 categories by using np.where() 2 times
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 0 1.331587 a 9 high 01_high 1 0.715279 a 7 high 01_high 2 -1.545400 a 1 low 03_low 3 -0.008384 a 5 low 02_medium 4 0.621336 a 7 high 02_medium 5 -0.720086 a 3 low 03_low 6 0.265512 a 6 high 02_medium 7 0.108549 a 5 low 02_medium 8 0.004291 a 5 low 02_medium 9 -0.174600 a 5 low 02_medium 10 0.433026 b 6 high 02_medium 11 1.203037 b 9 high 01_high 12 -0.965066 b 2 low 03_low 13 1.028274 b 8 high 01_high 14 0.228630 b 6 high 02_medium 15 0.445138 b 6 high 02_medium 16 -1.136602 b 2 low 03_low 17 0.135137 b 5 high 02_medium 18 1.484537 b 10 high 01_high 19 -1.079805 b 2 low 03_low
|
3개의 범주로 구분해서 새로 만든 'h_m_l' 이산형화 변환 변수를 기준으로 요약통계량을 계산해보면 아래와 같습니다.
In [28]: df.groupby('h_m_l')['C1'].size()
Out[28]:
h_m_l 01_high 5 02_medium 10 03_low 5
dtype: int64
In [29]: df.groupby('h_m_l')['C1'].mean()
Out[29]:
h_m_l 01_high 1.152543 02_medium 0.205863 03_low -1.089392
Name: C1, dtype: float64
In [30]: df.groupby('h_m_l')['C1'].std()
Out[30]:
h_m_l 01_high 0.296424 02_medium 0.242969 03_low 0.300877
Name: C1, dtype: float64
|
이상으로 이산형화(discretization) 변환에 대해서 마치도록 하겠습니다.
다음번 포스팅에서는 다항 차수 변환(polynomial variables transformation)에 대해서 알아보겠습니다.
많은 도움 되었기를 바랍니다.