이번 포스팅에서는 Python numpy 의 메소드, 함수 중에서 


- 최소값, 최대값, 혹은 조건에 해당하는 색인(index) 값을 찾기 

   : np.argmin(), np.argmax(), np.where()


- 최소값, 최대값, 혹은 조건에 맞는 값 찾기 

   : np.min(), np.max(), x[np.where()]


에 대해서 소개하겠습니다. 


분석할 때 꽤 많이 사용되므로 기억해두시면 좋겠습니다. 





  (1) 최소값(min), 최대값(max): np.min(), np.max()


x.min(), np.min(x), min(x) 모두 동일한 결과를 반환합니다. 



In [1]: import numpy as np


In [2]: x = np.array([5, 4, 3, 2, 1, 0])


In [3]: x.min()

Out[3]: 0


In [4]: np.min(x)

Out[4]: 0


In [5]: x.max()

Out[5]: 5


In [6]: np.max(x)

Out[6]: 5

 




  (2) 최소값, 최대값의 색인 위치: np.argmin(), np.argmax()



In [7]: x.argmin()

Out[7]: 5


In [8]: np.argmin(x)

Out[8]: 5


In [9]: x.argmax()

Out[9]: 0


In [10]: np.argmax(x)

Out[10]: 0

 




  (3) 조건에 맞는 값의 색인 위치: np.where()


배열에서 3과 같거나 큰 값을 가지는 색인의 위치를 알고 싶을 때, 


 

In [11]: np.where(x >= 3)

Out[11]: (array([0, 1, 2], dtype=int64),)




(4) 조건에 맞는 값을 indexing 하기: x[np.where()] 


배열에서 3과 같거나 큰 값을 indexing 하고 싶을 때, 



In [12]: x[np.where(x >= 3)]

Out[12]: array([5, 4, 3])

 




  (5) 조건에 맞는 값을 특정 다른 값으로 변환하기

     : np.where(조건, 조건에 맞을 때 값, 조건과 다를 때 값)


배열의 값이 3과 같거나 크면 3으로 변환하고, 3보다 작으면 그대로 값을 유지하고 싶을 때, 

(for loop & if else 조건문을 사용하는 것보다 수십배 빠르므로 매우 유용함)



In [13]: np.where(x >= 3, 3, x)

Out[13]: array([3, 3, 3, 2, 1, 0])

 


 

참고로, 위의 np.where를 사용한 배열 값 변환을 for loop & if else 조건문을 사용해서 써보면 아래와 같습니다. for loop은 데이터 사이즈가 커질 경우 속도가 매우 느려지므로, 위의 대용량 데이터는 벡터화된 연산을 하는 np.where() 함수 사용을 권합니다. .

 

 

In [14]: x_2 = []

    ...: for i in list(x):

    ...: if i >= 3:

    ...: x_2.append(3)

    ...: else:

    ...: x_2.append(i)

    ...:

    ...:


In [15]: x_2 = np.asarray(x_2)


In [16]: type(x_2)

Out[16]: numpy.ndarray


In [17]: x_2

Out[17]: array([3, 3, 3, 2, 1, 0])

 

 

많은 도움이 되었기를 바랍니다. 

 

728x90
반응형
Posted by Rfriend
,

지난번 포스팅에서는

 

 - 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_C1_C1_C1_C1_C1_C1_C1_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)에 대해서 알아보겠습니다.

 

많은 도움 되었기를 바랍니다.

 

 

 

728x90
반응형
Posted by Rfriend
,