지난번 포스팅에서는 Python sklearn.preprocessing.Binarizer() 를 사용해서 연속형 변수를 이항변수로 변환하는 방법을 소개하였습니다.

 

이번 포스팅에서는 Python sklearn.preprocessing.OneHotEncoder()를 사용해서 범주형 변수를 이항변수화(binarization of categorical feature) 하는 방법을 알아보겠습니다.

 

가령, 성별(gender)가 '남성(Male)'이면 '0', '여성(Female)'이면 '1'로 encoding 하고,

연령대(age group)가 '20대'이면 '0', '30대'이면 '1', '40대'이면 '2'로 encoding 하고,

등급(grade)가 'S'이면 '0', 'A'이면 '1', 'B'이면 '2', 'C'이면 '3', 'D'이면 '4'로 encoding 한다고 했을 때,

 

이를 value로 '0'과 '1'만을 가진 가변수(dummy variable)로 바꾸는 이항변수화했을 때의 예시가 아래의 이미지입니다.  이것을 Python은 자동으로(auto) 변수별 범주(catogory)의 종류, 개수를 파악해서 이항변수화 해줍니다. 아주 편해요.

 

 

 

 

위의 이미지에 나타난 예제 데이터를 가지고 sklearn.preprocessing.OneHotEncoder() 예를 들어보겠습니다.

 

먼저, 필요한 모듈을 불러오고, 예제 데이터 arrary를 만들어보겠습니다.

 

 

# importing modules

In [1]: from sklearn.preprocessing import OneHotEncoder


In [2]: import numpy as np

 


# making an example data arrary

In [3]: data_train = np.array([[0, 0, 0],

   ...: [0, 1, 1],

   ...: [0, 2, 2],

   ...: [1, 0, 3],

   ...: [1, 1, 4]])

   ...:


In [4]: data_train

Out[4]:

array([[0, 0, 0],
       [0, 1, 1],
       [0, 2, 2],
       [1, 0, 3],
       [1, 1, 4]])

 

 

 

 

  (1) OneHotEncoder() 로 범주형 변수의 이항변수화 적합시키기 : enc.fit()

 

 

# making the utility class OneHotEncoder

In [5]: enc= OneHotEncoder()

 

# fitting OneHotEncoder

In [6]: enc.fit(data_train)

Out[6]:

OneHotEncoder(categorical_features='all', dtype=<class 'float'>,

handle_unknown='error', n_values='auto', sparse=True)

 

 

 

 

  (2) 적합된(fitted) OneHotEncoder()의 Attributes 확인해보기

       : enc.active_features_ , enc.n_values_ , enc.feature_indices_

 

위의 이미지로 예를 들어보였던 범주형 변수의 '변환 이전' => 이항변수화 '변환 이후' 모습을 보면서 아래의 Attributes 결과를 비교해보면 이해하기가 수월할 거예요.

 


# Attributes : active_features_
#               - Indices for active features, actually occur in the training set

In [7]: enc.active_features_

Out[7]: array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], dtype=int64)

# 부연설명:  [남, 여, 20대, 30대, 40대, S, A, B, C, D]

 


# Attributes : n_values_
#                - Number of values per feature

In [8]: enc.n_values_

Out[8]: array([2, 3, 5])

# 부연설명: [성별 2개 범주, 연령대 3개 범주, 등급 5개 범주] 


# Attributes : feature_indices_
#                - Indices to feature ranges

In [9]: enc.feature_indices_

Out[9]: array([ 0, 2, 5, 10], dtype=int32)

# 부연설명: [성별 0이상~2미만, 연령대 2이상~5미만, 등급 5이상~10미만]

 

 

 

 

  (3) 적합된 OneHotEncoder()로 새로운 범주형 데이터셋을 이항변수화 변환하기

 

성별 '여성(1)', 연령대 '40대(2)', 등급 'D(4)' 의 범주형 속성을 가진 새로운 고객에 대해서 위의 (1)번에서 적합시킨 OneHotEncoder()의 enc.transform(new data).toarray()를 사용해서 이항변수화 시켜보겠습니다.

 

 

# new data : femail, age_group 40s, D grade

In [10]: data_new = np.array([[1, 2, 4]])

 

# applying OneHotEncoder to new data, returning array

In [11]: enc.transform(data_new).toarray()

Out[11]: array([[ 0., 1., 0., 0., 1., 0., 0., 0., 0., 1.]])

 

 

 

다음번 포스팅에서는 Python으로 연속형 변수를 다수개의 범주로 구분하는 이산형화(discretization) 방법에 대해서 알아보겠습니다.

 

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

 

 

728x90
반응형
Posted by Rfriend
,

지난번 포스팅에서는 Python sklearn.preprocessing.MinMaxScaler()를 사용해서 연속형 변수를 '최소~최대' 값이 '0~1' 사이 범위의 연속형 값을 가지도록 변환하는 [0~1] 변환에 대해서 알아보았습니다.

 

 

이번 포스팅에서는 Python sklearn.preprocessing.Binarizer()를 사용해서 연속형 변수를 특정 기준값 이하(equal or less the threshold)이면 '0', 특정 기준값 초과(above the threshold)이면 '1'의 두 개의 값만을 가지는 변수로 변환하는 방법을 소개하겠습니다.

 

확률변수 X가 이항분포(binomial distribution)를 따른다고 했을 때 '0' 또는 '1'의 값만을 가지는 이항변수화가 필요합니다.  참고로, 범주형 자료에 대한 회귀분석이나 연관성 분석, 텍스트 마이닝을 할 때도 '0'과 '1'의 값을 가지는 가변수(dummy variable)를 만들어서 분석하기도 합니다.

 

어떤 실험을 반복해서 시행한다고 했을 때 각 시행마다 "성공(success, 1)" 또는 "실패(failure, 0)"의 두 가지 경우의 수만 나온다고 할 때, 우리는 이런 시행을 "베르누이 시행(Bernoulli trial)"이라고 합니다. 

 

그리고 성공확률이 p인 베르누이 시행을 n번 반복했을 때 성공하는 횟수를 X라 하면, 확률변수 X는 모수 n과 p인 이항분포(Binomial distributio)을 따른다고 합니다. 

 

 

 

 

먼저 필요한 모듈을 불러오고, 아주 간단한 예제 array data를 만들어보겠습니다.

 

 

# importing modules

In [1]: import numpy as np


In [2]: from sklearn.preprocessing import Binarizer

 

# making a trainig data array

In [3]: X = np.array([[ 10., -10., 1.],

   ...: [ 5., 0., 2.],

   ...: [ 0., 10., 3.]])

   ...:


In [4]: X

Out[4]:

array([[ 10., -10.,   1.],
        [  5.,   0.,   2.],
        [  0.,  10.,   3.]])

 

 

 

 

 

  (1) sklearn.preprocessing.Binarizer() method를 사용한 이항변수화

 

 

 

# making the unitily class binarizer

In [5]: binarizer = Binarizer().fit(X)

 

# threshold=0.0 by default
In [6]: binarizer

Out[6]: Binarizer(copy=True, threshold=0.0)

 

# Feature values below or equal to the threshold are replaced by 0, above it by 1

In [7]: binarizer.transform(X)

Out[7]:

array([[ 1.,  0.,  1.],
       [ 1.,  0.,  1.],
       [ 0.,  1.,  1.]])

 

 

 

 

 

 

이항변수화를 하는 기준선(threshold)를 디폴트 '0.0'에서 '2.0'으로 조정해 보겠습니다.

 

 

In [8]: binarizer = Binarizer(threshold=2.0)


In [9]: X

Out[9]:

array([[ 10., -10.,   1.],
        [  5.,   0.,   2.],
        [  0.,  10.,   3.]])


In [10]: binarizer.transform(X)

Out[10]:

array([[ 1.,  0.,  0.],
        [ 1.,  0.,  0.],
        [ 0.,  1.,  1.]])

 

 

 

 

 

  (2) sklearn.preprocessing.binarize() 함수를 사용한 이항변수화

 

 

sklearn.preprocessing 모듈은 Transformer API 없이 이항변수화에 사용할 수 있는 binarize() 함수를 제공합니다.

 

 

# sklearn.preprocessing.binarize function which is used without transformer API
# sklearn.preprocessing.binarize(X, threshold=0.0, copy=True)

In [11]: from sklearn.preprocessing import binarize


In [12]: X

Out[12]:

array([[ 10., -10.,   1.],
       [  5.,   0.,   2.],
       [  0.,  10.,   3.]])


In [13]: binarize(X)

Out[13]:

array([[ 1.,  0.,  1.],
       [ 1.,  0.,  1.],
       [ 0.,  1.,  1.]])

 

 

 

이항변수화 기준선(threshold)를 기본값 '0.0'에서 '2.0'으로 조정해보겠습니다.

 

 

# adjusting the threshold of the binarizer

In [14]: binarize(X, threshold=2.0)

Out[14]:

array([[ 1.,  0.,  0.],
        [ 1.,  0.,  0.],
        [ 0.,  1.,  1.]])

 

# original data is not replaced by binarizer (compare it with 'copy=False' below exmaple
In [15]: X

Out[15]:

array([[ 10., -10.,   1.],
        [  5.,   0.,   2.],
        [  0.,  10.,   3.]])

 

 

 

 

 

 

binarize() 함수로 이항변수화할 때 복사(copy) 옵션의 기본값이 'True'이며, 원본 데이터는 그대로 두고 이항변수화 후의 값을 반환합니다.

 

binarize() 함수를 'copy = False' 로 설정하면 아래의 예시처럼 원본 데이터의 값 자체가 이항변수화 변환 후의 값으로 교체가 되어버립니다.

 

 

# # set to False to perform inplace binarization and avoid a copy

In [16]: binarize(X, threshold=2.0, copy=False)

Out[16]:

array([[ 1.,  0.,  0.],
        [ 1.,  0.,  0.],
        [ 0.,  1.,  1.]])

 

# oops, original data has been changed by binarizer
In [17]: X

Out[17]:

array([[ 1.,  0.,  0.],
        [ 1.,  0.,  0.],
        [ 0.,  1.,  1.]])

 

 

 

 

다음번 포스팅에서는 범주형 변수에 대한 이산형화, 이항변수화에 대해서 소개하겠습니다.

 

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

 

 

728x90
반응형
Posted by Rfriend
,

지난번 포스팅에서는 변수들의 척도(Scale)가 서로 다를 경우에 상호 비교를 위해서 표준화하는 방법으로서

 

  - 정규분포를 따르는 데이터의 표준정규분포로의 표준화 (z standardization)

    (평균과 표준편차 이용)

 

  - 이상치/특이값이 포함되어 있는 데이터의 표준화(scaling data with outliers)

    (중앙값과 IQR(InterQuartile Range) 이용)

 

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

 

이번 포스팅에서는 최소값(Min)과 최대값(Max)을 사용해서 '0~1' 사이의 범위(range)로 데이터를 표준화해주는 '0~1 변환'에 대해서 알아보겠습니다.  어디서 사용하나 싶을 텐데요, 요즘 각광받고 있는 인공신경망, 딥러닝 할 때 변수들을 '0~1' 범위로 변환해서 사용합니다.

 

Python은 '0~1' 범위 변환에 사용하는 

  - sklearn.preprocessing.MinMaxScaler() method

  - sklearn.preprocessing.minmax_scale() 함수

제공합니다.

 

 

 

 

먼저, 필요한 모듈을 불러오고, 실습에 사용할 array 데이터를 만들어보겠습니다.

 

 

# importing modules

In [1]: import numpy as np


In [2]: import pandas as pd


In [3]: from sklearn.preprocessing import MinMaxScaler

 

# making a trainig data array

In [4]: X = np.array([[ 10., -10., 1.],

   ...: [ 5., 0., 2.],

   ...: [ 0., 10., 3.]])

   ...:


In [5]: X

Out[5]:

array([[ 10., -10.,   1.],
        [  5.,   0.,   2.],
        [  0.,  10.,   3.]])

 

 

 

 

'0~1' 변환을 하는 3가지 방법을 차례대로 예를 들어서 소개하겠습니다.

 

 

  (1) 최소, 최대값을 구해서 '0~1' 범위로 변환

 

 

In [5]: X

Out[5]:

array([[ 10., -10.,   1.],
        [  5.,   0.,   2.],
        [  0.,  10.,   3.]])

 

# Scaling features to [0-1] range using the formula

In [6]: X_MinMax = (X - X.min(axis=0)) / (X.max(axis=0) - X.min(axis=0))


In [7]: X_MinMax

Out[7]:

array([[ 1. ,  0. ,  0. ],
        [ 0.5,  0.5,  0.5],
        [ 0. ,  1. ,  1. ]])

 

 

 

 

  (2) sklearn.preprocessing.MinMaxScaler() method를 사용한 최소.최대 '0~1' 범위 변환

 

training set에 대해 transformer API를 통해서 '0~1' 범위 변환을 훈련시키고 => 최소.최대 '0~1' 변환 모델을 test set (new data)에 대해 적용해서 '0~1' 범위 변환을 해보겠습니다.

 

 

In [5]: X

Out[5]:

array([[ 10., -10.,   1.],
        [  5.,   0.,   2.],
        [  0.,  10.,   3.]])

 

# min_max_scaler training using the transformer API

In [8]: min_max_scaler = MinMaxScaler()


In [9]: X_MinMax_train = min_max_scaler.fit_transform(X)


In [10]: X_MinMax_train

Out[10]:

array([[ 1. ,  0. ,  0. ],
       [ 0.5,  0.5,  0.5],
       [ 0. ,  1. ,  1. ]])

 

 

# making new test set

In [11]: X_new = np.array([[9., -10., 1.],

    ...: [5., -5., 3.],

    ...: [1., 0., 5.]])


In [12]: X_new

Out[12]:

array([[  9., -10.,   1.],
       [  5.,  -5.,   3.],
       [  1.,   0.,   5.]])

 


# applying min_max_scaler to test set (new data)

In [13]: X_MinMax_new = min_max_scaler.transform(X_new)


In [14]: X_MinMax_new

Out[14]:

array([[ 0.9 ,  0.  ,  0.  ],
       [ 0.5 ,  0.25,  1.  ],
       [ 0.1 ,  0.5 ,  2.  ]])

 

 

 

 

  (3) sklearn.preprocessing.minmax_scale() 함수를 사용한 최소.최대 '0~1' 범위 변환

 

sklearn.preprocessing.MinMaxScaler() method를 사용할 때 보다 조금 더 편한 면은 있으며, 결과는 동일합니다.

 

 

In [15]: X

Out[15]:

array([[ 10., -10.,   1.],
        [  5.,   0.,   2.],
        [  0.,  10.,   3.]])

 

# importing minmax_scale function from sklearn.preprocessing

In [16]: from sklearn.preprocessing import minmax_scale

 

# scaling X to min~max '0~1' range

In [17]: X_MinMax_scaled = minmax_scale(X, axis=0, copy=True)


In [18]: X_MinMax_scaled

Out[18]:

array([[ 1. ,  0. ,  0. ],
       [ 0.5,  0.5,  0.5],
       [ 0. ,  1. ,  1. ]])

 

 

 

다음번 포스팅에서는 이항변수화(binarization)에 대해서 알아보겠습니다.

 

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

 

 

 

728x90
반응형
Posted by Rfriend
,

지난번 포스팅에서는 zscore(), StandardScaler() 등을 사용해서 척도(scale)가 다른 변수들을 X ~ N(0, 1) 의 표준정규분포로 변환시키는 표준화에 대해서 알아보았습니다. 

 

그런데 표준정규분포로의 표준화 변환 시에는 "이상치, 특이값 (outlier)이 없어야 한다"는 가정사항이 있습니다.  표준정규분포로 변환하는 공식이 z = (x - mean) / std  이며, 평균(mean)은 이상치, 특이값에 엄청 민감하기 때문입니다.

 

그럼, 데이터에 "이상치"가 포함되어 있다면 어떻게 해야할까요?

 

첫번째 방법은 "이상치, 특이값을 찾아서 제거"한 후 표준정규분포로 표준화 변환을 해서 분석, 모델링을 진행하는 방법입니다.  "이상치, 특이값을 찾아서 제거"하는 노~력이 필요합니다. 물론,  회귀분석과 같은 parametric modeling 에서는 이상치 제거 후 모델링이 적합한 방법입니다.

 

두번째 방법은 "이상치, 특이값에 덜 민감한" 중앙값(median)과 IQR(Inter-Quartile Range)을 이용해서 척도를 표준화하는 방법입니다.  K-NN 같은 non-parametric modeling 은 두번째 방법도 써볼만 합니다.

 

이번 포스팅의 주제가 바로 두번째 방법에 대한 것입니다. 

 

이번 포스팅의 주인공은 RobustScaler() 이지만, 왜 필요하고 무엇이 표준정규분포 표준화와 다른지를 이해하기 쉽도록 하기 위해서, 이상치(outlier)를 포함하고 있는 동일한 예제 데이터에 대해서 Python 의 sklearn.preprocessing의

  (1) StandardScaler() method를 이용한 표준정규분포로의 표준화 ((x-mean)/std )와

  (2) RobustScaler() method를 이용한 표준화 ( (x-median)/IQR )를

비교하면서 설명을 해보겠습니다.

 

 

 

먼저, 필요한 모듈을 불러오고, 이상치, 특이값을 포함하고 있는 예제 데이터를 만들어보겠습니다.

 

 

# importing modules

In [1]: import numpy as np


In [2]: from sklearn.preprocessing import StandardScaler, RobustScaler


In [3]: import matplotlib.pyplot as plt


In [4]: import pandas as pd

 

# setting the number of digits of precision for floating point output

In [5]: np.set_printoptions(precision=2)

 

# setting random seed number

In [6]: np.random.seed(10)

 

# making 100 random x ~ N(10, 2)

In [7]: mu, sigma = 10, 2


In [8]: x = mu + sigma*np.random.randn(100)


In [9]: x

Out[9]:

array([ 12.66,  11.43,   6.91,   9.98,  11.24,   8.56,  10.53,  10.22,
        10.01,   9.65,  10.87,  12.41,   8.07,  12.06,  10.46,  10.89,
         7.73,  10.27,  12.97,   7.84,   6.04,   6.51,  10.53,  14.77,
        12.25,  13.35,  10.2 ,  12.8 ,   9.46,  11.23,   9.47,   8.9 ,
        10.27,   9.05,  12.62,  10.39,  10.8 ,   9.32,  12.51,   8.54,
        11.32,   9.3 ,   8.12,   9.02,   8.39,   9.57,   9.32,  10.62,
        11.13,   9.71,   9.95,  10.58,   8.92,  11.42,  11.68,  10.41,
        14.79,  11.83,   9.78,   9.28,   9.54,   9.  ,  12.26,   8.6 ,
         9.84,   8.94,  12.09,   7.16,   9.28,   9.76,  10.64,  10.92,
         9.57,  11.98,  10.63,  14.94,   6.98,  11.24,   7.91,   8.4 ,
        13.97,  13.49,   6.29,   9.55,   9.87,   5.74,   9.9 ,  10.79,
        10.43,   6.01,  12.22,  10.49,   9.88,   8.49,  11.42,  11.84,
         9.04,  10.18,  11.65,   6.09])

 


# plotting histogram

In [10]: plt.hist(x)

Out[10]:

(array([ 6., 3., 8., 15., 22., 20., 11., 9., 3., 3.]),

array([ 5.74, 6.66, 7.58, 8.5 , 9.42, 10.34, 11.26, 12.18,

13.1 , 14.02, 14.94]),

<a list of 10 Patch objects>)

 

# checking mean, std

In [11]: np.mean(x) # 10.15 (about 10)

Out[11]: 10.158833325873747


In [12]: np.std(x) # 1.93 (about 2)

Out[12]: 1.9340789542274115

 


# inserting outliers

In [13]: x[98:100] = 100


In [14]: x

Out[14]:

array([  12.66,   11.43,    6.91,    9.98,   11.24,    8.56,   10.53,
         10.22,   10.01,    9.65,   10.87,   12.41,    8.07,   12.06,
         10.46,   10.89,    7.73,   10.27,   12.97,    7.84,    6.04,
          6.51,   10.53,   14.77,   12.25,   13.35,   10.2 ,   12.8 ,
          9.46,   11.23,    9.47,    8.9 ,   10.27,    9.05,   12.62,
         10.39,   10.8 ,    9.32,   12.51,    8.54,   11.32,    9.3 ,
          8.12,    9.02,    8.39,    9.57,    9.32,   10.62,   11.13,
          9.71,    9.95,   10.58,    8.92,   11.42,   11.68,   10.41,
         14.79,   11.83,    9.78,    9.28,    9.54,    9.  ,   12.26,
          8.6 ,    9.84,    8.94,   12.09,    7.16,    9.28,    9.76,
         10.64,   10.92,    9.57,   11.98,   10.63,   14.94,    6.98,
         11.24,    7.91,    8.4 ,   13.97,   13.49,    6.29,    9.55,
          9.87,    5.74,    9.9 ,   10.79,   10.43,    6.01,   12.22,
         10.49,    9.88,    8.49,   11.42,   11.84,    9.04,   10.18,
        100.  ,  100.  ])

 


# checking change of mean and std

In [15]: np.mean(x) # 11.98

Out[15]: 11.981383595820532


In [16]: np.std(x) # 12.71

Out[16]: 12.714552555982538

 

# plotting histogram to see the change of distribution, especially by outliers

In [17]: plt.hist(x, bins=np.arange(0, 102, 2))

Out[17]:

(array([  0.,   0.,   1.,  10.,  36.,  34.,  14.,   3.,   0.,   0.,   0.,
          0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,
          0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,
          0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,
          0.,   0.,   0.,   0.,   0.,   2.]),
 array([  0,   2,   4,   6,   8,  10,  12,  14,  16,  18,  20,  22,  24,
         26,  28,  30,  32,  34,  36,  38,  40,  42,  44,  46,  48,  50,
         52,  54,  56,  58,  60,  62,  64,  66,  68,  70,  72,  74,  76,
         78,  80,  82,  84,  86,  88,  90,  92,  94,  96,  98, 100]),

<a list of 50 Patch objects>)

 

 

 

 

 

  (1) 이상치가 포함된 데이터의 표준정규분포로의 표준화 : 
       sklearn.preprocessing.
StandardScaler()

 

 

# reshape from 1d arrays to ndarray

In [18]: x = x.reshape(-1, 1)

 

# numpy.ndarray

In [19]: x[0:10]

Out[19]:

array([[ 12.66],
       [ 11.43],
       [  6.91],
       [  9.98],
       [ 11.24],
       [  8.56],
       [ 10.53],
       [ 10.22],
       [ 10.01],
       [  9.65]])

 

# By StandardScaler()

In [20]: x_StandardScaler = StandardScaler().fit_transform(x)


In [21]: x_StandardScaler

Out[21]:
array([[  5.36e-02],
       [ -4.33e-02],
       [ -3.99e-01],
       [ -1.57e-01],
       [ -5.81e-02],
       [ -2.69e-01],
       [ -1.14e-01],
       [ -1.39e-01],
       [ -1.55e-01],
       .....

       ..... (중간 생략)

       .....

       [ -4.38e-02],
       [ -1.14e-02],
       [ -2.32e-01],
       [ -1.42e-01],
       [  6.92e+00],
       [  6.92e+00]])

 


# checking mean and std, z ~ N(0, 1)

In [22]: np.mean(x_StandardScaler) # mean = 0

Out[22]: 5.3290705182007512e-17


In [23]: np.std(x_StandardScaler) # std = 1

Out[23]: 1.0

 


# look at the outliers at the right corner

In [24]: plt.hist(x_StandardScaler)

Out[24]:

(array([ 98., 0., 0., 0., 0., 0., 0., 0., 0., 2.]),

array([-0.49, 0.25, 0.99, 1.73, 2.47, 3.22, 3.96, 4.7 , 5.44,

6.18, 6.92]),

<a list of 10 Patch objects>)

 

 

# zoom in

In [25]: x_StandardScaler_zoonin = x_StandardScaler[x_StandardScaler < 5]


In [26]: plt.hist(x_StandardScaler_zoonin, bins=np.arange(-3.0, 3.0, 0.2))

Out[26]:

(array([ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.,

0., 5., 26., 50., 14., 3., 0., 0., 0., 0., 0.,

0., 0., 0., 0., 0., 0., 0.]),

array([ -3.00e+00, -2.80e+00, -2.60e+00, -2.40e+00, -2.20e+00,

-2.00e+00, -1.80e+00, -1.60e+00, -1.40e+00, -1.20e+00,

-1.00e+00, -8.00e-01, -6.00e-01, -4.00e-01, -2.00e-01,

2.66e-15, 2.00e-01, 4.00e-01, 6.00e-01, 8.00e-01,

1.00e+00, 1.20e+00, 1.40e+00, 1.60e+00, 1.80e+00,

2.00e+00, 2.20e+00, 2.40e+00, 2.60e+00, 2.80e+00]),

<a list of 29 Patch objects>)

 

 

 

 

위의 '표준정규분포로의 표준화' 예시의 제일 마지막에 이상치(outlier)를 무시하고 표준화 이후 값 범위 (-3 ~ 3) 사이로 그린 히스토그램을 아래의 RobustScaler()로 표준화를 한 값과 비교해보시기 바랍니다. 

StandardScaler() 에 의한 표준화가 이상치에 영향을 더 심하게 받아서 이상치가 아닌 값들이 조밀하게, 촘촘하게 서로 붙어있음을 알 수 있습니다.

 

 

 

  (2) 이상치가 포함된 데이터의 중앙값과 IQR 를 이용한 표준화

      : sklearn.preprocessing.RobustScaler()

 

 

In [27]: np.median(x) # 10.2

Out[27]: 10.207697741550213


In [28]: Q1 = np.percentile(x, 25, axis=0)


In [29]: Q1 # 9.04

Out[29]: array([ 9.04])


In [30]: Q3 = np.percentile(x, 75, axis=0) # 5.700


In [31]: Q3 # 11.4

Out[31]: array([ 11.42])


In [32]: IQR = Q3 - Q1


In [33]: IQR # 2.37

Out[33]: array([ 2.37])


In [34]: x_RobustScaler = RobustScaler().fit_transform(x)

 

# list up 10 elememts from backward

In [35]: x_RobustScaler[-10:]

Out[35]:

array([[  8.46e-01],
       [  1.19e-01],
       [ -1.40e-01],
       [ -7.23e-01],
       [  5.12e-01],
       [  6.86e-01],
       [ -4.94e-01],
       [ -1.20e-02],
       [  3.78e+01],
       [  3.78e+01]])

 

# RobustScaler() removes the median and scales the data according to IQR(Inerquartile Range)

In [36]: np.median(x_RobustScaler)

 

Out[36]: 0.0


In [37]: np.mean(x_RobustScaler)

Out[37]: 0.74729363822182793


In [38]: np.std(x_RobustScaler)

Out[38]: 5.3569262082386482

 

# checking the distribution by histogram after RobustScaler

In [39]: plt.hist(x_RobustScaler)

Out[39]:

(array([ 98.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,   2.]),
 array([ -1.88,   2.09,   6.06,  10.03,  14.  ,  17.97,  21.95,  25.92,
         29.89,  33.86,  37.83]),
 <a list of 10 Patch objects>)

 

 

# zoom in

In [40]: x_RobustScaler_zoonin = x_RobustScaler[x_RobustScaler < 5]


In [41]: plt.hist(x_RobustScaler_zoonin, bins=np.arange(-3, 3, 0.2))

Out[41]:

(array([  0.,   0.,   0.,   0.,   0.,   1.,   3.,   1.,   3.,   1.,   4.,
          6.,   7.,  13.,  11.,  14.,   6.,   7.,   6.,   5.,   4.,   2.,
          1.,   0.,   3.,   0.,   0.,   0.,   0.]),
 array([ -3.00e+00,  -2.80e+00,  -2.60e+00,  -2.40e+00,  -2.20e+00,
         -2.00e+00,  -1.80e+00,  -1.60e+00,  -1.40e+00,  -1.20e+00,
         -1.00e+00,  -8.00e-01,  -6.00e-01,  -4.00e-01,  -2.00e-01,
          2.66e-15,   2.00e-01,   4.00e-01,   6.00e-01,   8.00e-01,
          1.00e+00,   1.20e+00,   1.40e+00,   1.60e+00,   1.80e+00,
          2.00e+00,   2.20e+00,   2.40e+00,   2.60e+00,   2.80e+00]),
 <a list of 29 Patch objects>)

 

 

 

아래의 두 개의 히스토그램은 이상치, 특이값(outlier)이 포함되어 있는 데이터를 표준화하는 경우에 (1) 평균과 표준편차를 이용한 표준정규분포 표준화 결과 (outlier 미포함한 범위의 zoom in)와, (2) 중앙값과 IQR(Interquartile Range)를 이용한 이상치에 견고한 표준화 (outlier 미포함한 범위의 zoom in) 결과의 분포를 나타내고 있습니다.

 

왼쪽의 StandardScaler()에 의한 표준화보다 오른쪽의 RobustScaler()에 의한 표준화가 동일한 값을 더 넓게 분포시키고 있음을 알 수 있습니다.  즉, 목표변수 y값을 분류나 예측하는데 있어 산포가 더 크기 때문에 설명변수 x변수로서 더 유용할 수 있다고 추정할 수 있습니다.

 

 

(1) StandardScaler() zoon in

(2) RobustScaler() zoon in 

 

 

 

 

 

 

다음번 포스팅에서는 최소.최대 [0~1] 범위 변환에 대해서 소개하도록 하겠습니다.

 

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

 

 

 

728x90
반응형
Posted by Rfriend
,

데이터 분석을 하다 보면 변수들 간의 척도 (scale) 가 서로 다른 경우 직접적으로 상호 비교를 할 수가 없습니다.  모델링에서는 척도(scale)가 다름으로 인해서 모수의 왜곡이 생길 수도 있습니다.

 

따라서 모델링 작업에 들어가기 전에 변수들 간의 척도가 다른 경우에는 보통 표준화(scale standization)를 진행합니다.

 

표준화 중에서도 모집단이 '정규분포 (normal distribution, Gaussian distribution)을 따르는 경우 평균이 0, 표준편차는 1 인 표준정규분포(standard normal distribution)로 표준화 하는 방법을 많이 사용합니다. 

 

이번 포스팅에서는

 

 - Numpy : z = (x - mean())/std()

 - scipy.stats : zscore()

 - sklearn.preprocessing : StandardScaler().fit_transform()

 

의 모듈, method를 이용한 표준정규분포 표준화 (mean removal and variance scaling, mean = 0, std = 1)에 대해서 소개하겠습니다.

 

 

 

 

실습에 필요한 모듈을 importing하고 예제 Dataset을 만들어보겠습니다.

 

 

In [1]: import numpy as np


In [2]: data = np.random.randint(30, size=(6, 5))


In [3]: data

Out[3]:

array([[ 3,  5, 14, 24, 24],
       [ 3,  9,  1, 20,  3],
       [10,  5, 11, 17, 28],
       [26,  9, 20, 10,  8],
       [15,  7,  1, 24,  2],
       [15, 19, 10, 13,  2]])

 

 

 

표준정규분포로 표준화하는 3가지 방법을 차례대로 소개하겠습니다.

 

 

  (1) Numpy 를 이용한 표준화 : z = (x - mean())/std()

 

칼럼마다 각각의 평균, 표준편차를 적용해서 표준화를 하려면 mean(data, axis=0), std(data, axis=0) 처럼 'axis=0' 을 설정해주면 됩니다.

 

 

# (1) Using numpy, z = (x-mean)/std

In [4]: from numpy import *


In [5]: data_standadized_np = (data - mean(data, axis=0)) / std(data, axis=0)


In [6]: data_standadized_np

Out[6]:

array([[-1.13090555, -0.84016805,  0.66169316,  1.14070365,  1.19426502],
       [-1.13090555,  0.        , -1.24986486,  0.38023455, -0.75998683],
       [-0.25131234, -0.84016805,  0.22056439, -0.19011728,  1.56650347],
       [ 1.75918641,  0.        ,  1.54395071, -1.5209382 , -0.29468877],
       [ 0.37696852, -0.42008403, -1.24986486,  1.14070365, -0.85304644],
       [ 0.37696852,  2.10042013,  0.07352146, -0.95058638, -0.85304644]])

 

# check of 'mean=0', 'standard deviation=1'

In [7]: mean(data_standadized_np, axis=0)

Out[7]:

array([ -5.55111512e-17,   0.00000000e+00,   9.25185854e-18,
         0.00000000e+00,   3.70074342e-17])


In [8]: std(data_standadized_np, axis=0)

Out[8]: array([ 1.,  1.,  1.,  1.,  1.])

 

 

  • 평균(mean): np.mean(arr)
  • 표준편차(standard deviation): np.std(arr)
  • 분산(variance): np.var(arr)


import numpy as np

arr = np.array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10])


print('mean:', np.mean(arr))

print('standard deviation:', np.std(arr))

print('variance:', np.var(arr))


mean: 5.0
standard deviation: 3.1622776601683795
variance: 10.0

 


 


 

  (2) scipy.stats 을 이용한 표준화 : ss.zscore()

 

 

# (2) Standardization using zscore() of scipy.stats

In [9]: import scipy.stats as ss


In [10]: data_standadized_ss = ss.zscore(data)


In [11]: data_standadized_ss

Out[11]:

array([[-1.13090555, -0.84016805,  0.66169316,  1.14070365,  1.19426502],
       [-1.13090555,  0.        , -1.24986486,  0.38023455, -0.75998683],
       [-0.25131234, -0.84016805,  0.22056439, -0.19011728,  1.56650347],
       [ 1.75918641,  0.        ,  1.54395071, -1.5209382 , -0.29468877],
       [ 0.37696852, -0.42008403, -1.24986486,  1.14070365, -0.85304644],
       [ 0.37696852,  2.10042013,  0.07352146, -0.95058638, -0.85304644]])

 

 

 

 

  (3) sklearn.preprocessing 을 이용한 표준화 : StandardScaler().fit_transform()

 

 

In [12]: from sklearn.preprocessing import StandardScaler


In [13]: data_standadized_skl = StandardScaler().fit_transform(data)

 

In [14]: data_standadized_skl

Out[14]:

array([[-1.13090555, -0.84016805,  0.66169316,  1.14070365,  1.19426502],
       [-1.13090555,  0.        , -1.24986486,  0.38023455, -0.75998683],
       [-0.25131234, -0.84016805,  0.22056439, -0.19011728,  1.56650347],
       [ 1.75918641,  0.        ,  1.54395071, -1.5209382 , -0.29468877],
       [ 0.37696852, -0.42008403, -1.24986486,  1.14070365, -0.85304644],
       [ 0.37696852,  2.10042013,  0.07352146, -0.95058638, -0.85304644]])

 

 

 

다음번 포스팅에서는 데이터셋에 Outlier 가 들어있을 때 Robust하게 표준화할 수 있는 방법으로서 sklearn.preprocessing.robust_scale, sklearn.preprocessing.RobustScaler 을 소개하겠습니다.

 

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

 

 

 

728x90
반응형
Posted by Rfriend
,

지난번 포스팅에서는 중복값 확인, 중복값 처리에 대해서 알아보았습니다.

 

이번 포스팅에서는 유일한 값(unique value)을 찾고 개수도 세어보기 위해서 Python pandas의

 

 - pd.Series.unique() 를 이용한 유일한 값 찾기

   (Return np.ndarray of unique values in the object)

 

 - pd.Series.value_counts() 를 이용한 유일한 값별 개수 세기

   (Returns object containing counts of unique values)

 

를 소개하겠습니다. 

 

 

 

데이터 전처리 및 탐색적 데이터 분석 단계에서 종종 사용하니 알아두면 좋겠습니다.

 

 

먼저, 필요한 모듈 불러오고, 예제 DataFrame을 만들어보겠습니다.

 

 

In [1]: import pandas as pd


In [2]: import numpy as np


In [3]: df = pd.DataFrame({'A': ['A1', 'A1', 'A2', 'A2', 'A3', 'A3'],

   ...: 'B': ['B1', 'B1', 'B1', 'B1', 'B2', np.nan],

   ...: 'C': [1, 1, 3, 4, 4, 4]})


In [4]: df

Out[4]:

    A    B  C
0  A1   B1  1
1  A1   B1  1
2  A2   B1  3
3  A2   B1  4
4  A3   B2  4
5  A3  NaN  4

 

 

 

 

  (1) 유일한 값 찾기 : pd.Series.unique()

 

pd.Series.unique()는 np.ndarray를 반환합니다. DataFrame의 각 칼럼별로 indexing해서 unique()를 적용한 결과는 아래와 같습니다.

 

'B' 칼럼에 'NaN'도 unique()에 포함되었습니다.

 

 

In [5]: df['A'].unique()

Out[5]: array(['A1', 'A2', 'A3'], dtype=object)


In [6]: df['B'].unique()

Out[6]: array(['B1', 'B2', nan], dtype=object)


In [7]: df['C'].unique()

Out[7]: array([1, 3, 4], dtype=int64)

 

 

 

 

  (2) 유일한 값별로 개수 세기 : pd.Series.value_counts()

 

 

# eturns object containing counts of unique values

pd.Series.value_counts(normalize=False, # False면 개수, True면 상대 비율 구함

                              sort=True, # True면 개수 기준 정렬, False면 유일한 값 기준 정렬

                              ascending=False, # False면 내림차순 정렬, True면 오름차순 정렬

                          bins=None, # None이면 유일값 기준 개수, None아니면 Bins Group별 개수

                              dropna=True # True면 NaN 무시, False면 유일값에 NaN 포함)

 

 

 

 

In [4]: df

Out[4]:

    A    B  C
0  A1   B1  1
1  A1   B1  1
2  A2   B1  3
3  A2   B1  4
4  A3   B2  4
5  A3  NaN  4

 

# returns of pd.Series.value_counts() by default setting

In [8]: df['A'].value_counts()

Out[8]:

A3    2
A2    2
A1    2

Name: A, dtype: int64


In [9]: df['B'].value_counts()

Out[9]:

B1    4
B2    1

Name: B, dtype: int64


In [10]: df['C'].value_counts()

Out[10]:

4    3
1    2
3    1

Name: C, dtype: int64

 

 

 

 

  (2-1) 유일 값 별 상대적 비율 : pd.Series.value_counts(normalize=True)

 

 

In [4]: df

Out[4]:

    A    B   C
0  A1   B1  1
1  A1   B1  1
2  A2   B1  3
3  A2   B1  4
4  A3   B2  4
5  A3  NaN  4

 

In [11]: df['C'].value_counts(normalize=True)

Out[11]:

4    0.500000
1    0.333333
3    0.166667

Name: C, dtype: float64

 

 

 

 

  (2-2) 유일한 값 기준 정렬 : pd.Series.value_counts(sort=True, ascending=True)

 

sort=True, False 와 ascending=True, False 의 조합은 아래 예시의 3가지 경우의 수가 있습니다. 

 

[12] : 유일한 값의 개수 기준 내림차순 정렬 예시 (sort descending order by value_counts)

[13] : 유일한 값의 개수 기준 오름차순 정렬 예시 (sort ascending order by value_counts)

[14] : 유일한 값 기준 오름차순 정렬 예시 (유일한 값의 개수 기준 정렬은 없음)

 

 

In [4]: df

Out[4]:

    A    B   C
0  A1   B1  1
1  A1   B1  1
2  A2   B1  3
3  A2   B1  4
4  A3   B2  4
5  A3  NaN  4

 

# sort descending order by value_counts

In [12]: df['C'].value_counts(sort=True, ascending=False) # by default

Out[12]:

4    3
1    2
3    1

Name: C, dtype: int64

 

# sort ascending order by value_counts

In [13]: df['C'].value_counts(sort=True, ascending=True)

Out[13]:

3    1
1    2
4    3

Name: C, dtype: int64

 

# Don't sort by value_counts, but sort by unique value

In [14]: df['C'].value_counts(sort=False)

Out[14]:

1    2
3    1
4    3

Name: C, dtype: int64

 

 

 

 

  (2-3) 결측값을 유일한 값에 포함할지 여부 : pd.Series.value_counts(dropna=True)

 

 

In [4]: df

Out[4]:

    A    B   C
0  A1   B1  1
1  A1   B1  1
2  A2   B1  3
3  A2   B1  4
4  A3   B2  4
5  A3  NaN  4

 

# dropna=True : Don’t include counts of NaN

In [15]: df['B'].value_counts(dropna=True) # by default

Out[15]:

B1    4
B2    1

Name: B, dtype: int64

 

# dropna=False : Include counts of NaN

In [16]: df['B'].value_counts(dropna=False)

Out[16]:

B1     4
B2     1
NaN    1

Name: B, dtype: int64

 

 

 

 

  (2-4) Bins Group별 값 개수 세기 : pd.Series.value_counts(bins=[ , , ,])

 

 

In [4]: df

Out[4]:

    A    B   C
0  A1   B1  1
1  A1   B1  1
2  A2   B1  3
3  A2   B1  4
4  A3   B2  4
5  A3  NaN  4

 

In [17]: df['C'].value_counts(bins=[0, 1, 2, 3, 4, 5], sort=False)

Out[17]:

0 2

1 0

2 1

3 3

4 0

Name: C, dtype: int64

 

 

 

아래의 pd.cut(Series, bins=[ , , , ]) 와 위의 결과가 동일하며, 위의 Series.value_counts(bins=[ , , , ])가 조금 더 사용하기 편리합니다.

 

 

In [18]: out = pd.cut(df['C'], bins=[0, 1, 2, 3, 4, 5])


In [19]: pd.value_counts(out)

Out[19]:

(3, 4] 3

(0, 1] 2

(2, 3] 1

(4, 5] 0

(1, 2] 0

Name: C, dtype: int64

 

 

 

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

 

 

728x90
반응형
Posted by Rfriend
,

데이터를 수집하는 과정 중의 오류, 데이터를 병합하는 과정에서의 오류 등으로 인해서 중복되지 않아야 할 데이터가 중복이 되는 경우가 생길 수 있습니다.

 

특히, unique 한 'key' 값을 관리해야 하는 경우 중복(duplicates)이 발생하면 분석에 심각한 영향을 끼칠 수도 있습니다.  (관계형 DB라면 아례 데이터가 들어가지도 않겠지요...)

 

따라서 본격적인 데이터 분석에 들어가기 전에 반드시, 꼭, 예외없이, 무조건, Seriously 중복 데이터를 확인하고 처리하는 전처리 작업이 필요합니다.  (가령, 두 개의 DataFrame을 Left Join 으로 Merge했더니 row의 개수가 늘어났다 하면 그건 병합하는 DataFrame의 'key' 값에 중복이 있다는 얘기거든요.)

 

데이터 개수가 몇 개 안되면 눈으로 확인하고 중복 데이터 위치 indexing 해서 처리하면 되는데요, 데이터 개수가 많으면 육안으로 일일이 확인한다는게 사실상 불가능해집니다.

 

이때 중복이 존재하는지 확인할 때 사용할 수 있는 것이 Python pandas의 duplicated() method 입니다.  그리고 중복값을 처리하는 것이 drop_duplicates() method 이구요.

 

 - 중복 여부 확인 : DataFrame.duplicated()

 - 중복이 있으면 처음과 마지막 값 중 무엇을 남길 것인가? : keep = 'first', 'last', False

 - 중복값 처리(unique한 1개의 key만 남기고 나머지 중복은 제거) : DataFrame.drop_duplicates()

 

 

 

 

먼저 pandas 모듈을 불러오고, 예제로 사용할 '중복(duplicate entries)'이 있는 DataFrame을 만들어보겠습니다.

 



In [1]: import pandas as pd


In [2]: data = {'key1':['a', 'b', 'b', 'c', 'c'],
   ...: 'key2':['v', 'w', 'w', 'x', 'y'],
   ...: 'col':[1, 2, 3, 4, 5]}


In [3]: df = pd.DataFrame(data, columns=['key1','key2','col'])


In [4]: df
Out[4]:
  key1 key2  col
0    a    v    1
1    b    w    2
2    b    w    3
3    c    x    4
4    c    y    5




 

 

 

  (1) 중복 데이터가 있는지 확인하기 : DataFrame.duplicated()

 

'key1'을 기준으로 하면 index 1, 2 ('b')가 중복, index 3, 4 ('c')가 서로 중복입니다.

'key1'과 'key2'를 동시에 기준으로 하면 index 1, 2 ('b', 'w') 가 서로 중복입니다.

 

DataFrame.duplicated() method는 True, False 의 boolean 형태의 Series를 반환합니다.

 



In [5]: df.duplicated(['key1'])
Out[5]:
0    False
1    False
2     True
3    False
4     True
dtype: bool





In [6]: df.duplicated(['key1', 'key2'])
Out[6]:
0    False
1    False
2     True
3    False
4    False
dtype: bool




 

 

 

  (2) 중복이 있으면 처음과 끝 중 무슨 값을 남길 것인가? : keep = 'first', 'last', False

 

keep='first'가 default 이며, 중복값이 있으면 첫번째 값을 duplicated 여부를 False로 반환하고, 나머지 중복값에 대해서는 True를 반환하게 됩니다. keep='last'는 그 반대이겠지요.

 

keep=False는 처음이나 끝값인지 여부는 고려를 안하고 중복이면 무조건 True를 반환합니다 (=> 나중에 drop_duplicates() 에서 keep 할 생각이 없다는 뜻입니다).

 



In [7]: df.duplicated(['key1'], keep='first') # by default
Out[7]:
0    False
1    False
2     True
3    False
4     True
dtype: bool




 

In [8]: df.duplicated(['key1'], keep='last')
Out[8]:
0    False
1     True
2    False

3     True
4    False
dtype: bool
 
 


In [9]: df.duplicated(['key1'], keep=False)
Out[9]:
0    False
1     True
2     True
3     True
4     True

dtype: bool




 

 

 

  (3) 중복값 처리(unique한 1개의 key만 남기고 나머지 중복은 제거) 
       : DataFrame.drop_duplicates()

 

drop_duplicates() method는 중복값을 keep='first', 'last', False argument에 따라서 unique한 1개의 key값만 남기고 나머지 중복은 제거를 한 후의 DataFrame을 반환합니다.

 



# drop duplic
In [10]: df.drop_duplicates(['key1'], keep='first')
Out[10]:
  key1 key2  col
0    a    v    1
1    b    w    2
3    c    x    4





In [11]: df.drop_duplicates(['key1'], keep='last')
Out[11]:
  key1 key2  col
0    a    v    1
2    b    w    3
4    c    y    5





In [12]: df.drop_duplicates(['key1'], keep=False)
Out[12]:
  key1 key2  col
0    a    v    1



 

 

 

이상으로 중복 여부 확인, 중복값 처리를 위한 Python pandas의 DataFrame.duplicated(), DataFrame.drop_duplicates() method에 대한 소개를 마치겠습니다.

 

 

 

 

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

 

 

 

 

728x90
반응형
Posted by Rfriend
,

지난번 포스팅에서는 Python pandas의

 

 - fillna() method를 사용한 결측값 대체

 - dropna() method를 사용한 결측값 있는 행, 열 제거

 - interpolate() method를 사용한 결측값 보간

 

하는 방법을 알아보았습니다.

 

이번 포스팅에서는 Python pandas의 replace() method를 사용해서

 

 - 결측값 혹은 원래의 값을 다른 값으로 교체(replacing generic values)

 - List 를 다른 List로 교체

 - mapping dict 로 교체

 - DataFrame의 특정 칼럼 값 교체

 

하는 방법을 소개하겠습니다.

 

fillna() 를 사용한 결측값 대체와 replace()를 사용한 결측값 교체가 유사한면이 있구요, 다만 replace() 는 결측값 말고도 모든 값을 대상으로 할 수 있고, list, mapping dict 등으로 좀더 유연하고 포괄적으로 사용할 수 있는 장점이 있습니다.

 

 

 

 

replace() method를 가지고 결측값, 실측값 모두를 대상으로 교체(replacement)하는 예를 들어보겠습니다.  필요한 모듈을 importing하고, 결측값을 포함한 간단한 Series 먼저 시작하겠습니다.

 

 

In [1]: import pandas as pd


In [2]: import numpy as np


In [3]: from pandas import DataFrame, Series

 

In [4]: ser = Series([1, 2, 3, 4, np.nan])

 

In [5]: ser

Out[5]:

0    1.0
1    2.0
2    3.0
3    4.0
4    NaN
dtype: float64

 

 

 

 

  (1) 결측값, 실측값을 다른 값으로 교체하기 : replace(old_val, new_val)

 

 

# replacing a value with other value

In [6]: ser.replace(2, 20)

Out[6]:

0     1.0
1    20.0
2     3.0
3     4.0
4     NaN
dtype: float64

 

# replacing missing value(NaN) with other value

In [7]: ser.replace(np.nan, 5)

Out[7]:

0    1.0
1    2.0
2    3.0
3    4.0
4    5.0
dtype: float64

 

 

 

 

 

  (2) list 를 다른 list 값으로 교체하기 : replace([old1, old2, ...], [new1, new2, ...])

 

 

In [8]: ser

Out[8]:

0    1.0
1    2.0
2    3.0
3    4.0
4    NaN
dtype: float64

 

In [9]: ser.replace([1, 2, 3, 4, np.nan], [6, 7, 8, 9, 10])

Out[9]:

0     6.0
1     7.0
2     8.0
3     9.0
4    10.0
dtype: float64

 

 

 

 

  (3) mapping dict 로 원래 값, 교체할 값 매핑 : replace({old1 : new1, old2: new2})

 

 

In [10]: ser

Out[10]:

0    1.0
1    2.0
2    3.0
3    4.0
4    NaN
dtype: float64

 

In [11]: ser.replace({1: 6,

    ...: 2: 7,

    ...: 3: 8,

    ...: 4: 9,

    ...: np.nan: 10})

Out[11]:

0     6.0
1     7.0
2     8.0
3     9.0
4    10.0
dtype: float64

 

 

 

 

  (4) DataFrame의 특정 칼럼 값 교체하기 : df.replace({'col1': old_val}, {'col1': new_val})

 

DataFrame 의 값을 교체하려면 dict { } 안에 원래와 교체할 'column name'과 'value' 를 짝을 이루어서 매핑해주면 됩니다.

 

 

In [13]: df = DataFrame({'C1': ['a_old', 'b', 'c', 'd', 'e'],

    ...: 'C2': [1, 2, 3, 4, 5],

    ...: 'C3': [6, 7, 8, 9, np.nan]})


In [14]: df

Out[14]:

      C1  C2   C3
a_old   1  6.0
1      b   2  7.0
2      c   3  8.0
3      d   4  9.0
4      e   5  NaN

 

In [15]: df.replace({'C1': 'a_old'}, {'C1': 'a_new'})

Out[15]:

      C1  C2   C3
a_new   1  6.0
1      b   2  7.0
2      c   3  8.0
3      d   4  9.0
4      e   5  NaN


In [16]: df.replace({'C3': np.nan}, {'C3': 10})

Out[16]:

      C1  C2    C3
0  a_old   1   6.0
1      b   2   7.0
2      c   3   8.0
3      d   4   9.0
4      e   5  10.0

 

 

 

이상으로 Python pandas의 replace() method를 사용해서 결측값, 원래 값을 다른 값으로 교체하기 소개를 마치겠습니다.

 

결측값을 그룹별로 그룹별 평균으로 대체하기는 http://rfriend.tistory.com/402 를 참고하세요. 


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

 

 

 

728x90
반응형
Posted by Rfriend
,

지난번 포스팅에서는 Python pandas 의 dropna() method를 사용해서

 

 - 결측값이 들어있는 행 전체 제거하기

 - 결측값이 들어있는 열 전체 제거하기

 

방법을 알아보았습니다.

 

 

이번 포스팅에서는 Python pandas의 interpolate() method를 사용해서 결측값을 보간하는 방법(interpolation of missing values)에 대해서 소개하겠습니다.

 

 - (1) 시계열데이터의 값에 선형으로 비례하는 방식으로 결측값 보간

       (interpolate TimeSeries missing values linearly)

 - (2) 시계열 날짜 index를 기준으로 결측값 보간

       (interploate TimeSeries missing values along with Time-index)

 - (3) DataFrame 값에 선형으로 비례하는 방식으로 결측값 보간

       (interpolate DataFrame missing values linearly)

 - (4) 결측값 보간 개수 제한하기

       (limit the number of consecutive interpolation)

 

 

시계열 데이터 분석이라든지 (X, Y, Z) 좌표 공간 상에서 측정된 데이터(근접한 공간 상 데이터 간 상관성/연속성이 있는 경우) 등에서 사용하면 매우 유용하고 편리한 method 입니다.

 

 

이전 포스팅의 결측값 대체는 '특정의 동일 값'으로 채우는 방식(filling, imputation)이었던 반면에, 이번 포스팅의 결측값 보간(interploation)은 실측값과 실측값 사이의 결측값을 마치 '그라데이션(gradation)' 기법으로 색깔을 조금씩 변화시켜가면서 부드럽게 채워나가는 방법이라고 이해하시면 되겠습니다.

 

 

 

자, 그럼 필요한 모듈을 import 하고, 결측값이 들어있는 TimeSeries 데이터를 만든 후에, 결측값을 보간해보겠습니다.

 

  (1) 시계열데이터의 값에 선형으로 비례하는 방식으로 결측값 보간
       (interpolate TimeSeries missing values linearly) : ts.interpolate()

 



# importing modules 
In [1]: import pandas as pd


In [2]: import numpy as np


In [3]: from pandas import DataFrame, Series


In [4]: from datetime import datetime


# making TimeSeries with missing values
In [5]: datestrs = ['12/1/2016', '12/03/2016', '12/04/2016', '12/10/2016']


In [6]: dates = pd.to_datetime(datestrs)


In [7]: dates
Out[7]: DatetimeIndex(['2016-12-01', '2016-12-03', '2016-12-04', '2016-12-10'], dtype='datetime64[ns]', freq=None)


In [8]: ts = Series([1, np.nan, np.nan, 10], index=dates)


In [9]: ts
Out[9]:
2016-12-01     1.0
2016-12-03     NaN
2016-12-04     NaN

2016-12-10    10.0
dtype: float64




 

 

ts.interpolote() 는 default 가 interpolate(method='values')로서 선형으로 비례하여 결측값을 보간해줍니다.

 



# interpolate missing values linearly 
In [10]: ts_intp_linear = ts.interpolate()


In [11]: ts_intp_linear
Out[11]:
2016-12-01     1.0
2016-12-03     4.0
2016-12-04     7.0
2016-12-10    10.0




 

 

 

  (2) 시계열 날짜 index를 기준으로 결측값 보간
       (interploate TimeSeries missing values along with Time-index)
       : ts.interploate(method='time')

 

위의 ts.interpolate() 결과와 아래의 ts.interpolate(method='time') 보간 결과를 유심히 비교해보시기 바랍니다.

 



In [12]: ts
Out[12]:
2016-12-01     1.0
2016-12-03     NaN
2016-12-04     NaN
2016-12-10    10.0



dtype: float64


In [13]: ts_intp_time = ts.interpolate(method='time')


In [14]: ts_intp_time
Out[14]:
2016-12-01     1.0
2016-12-03     3.0
2016-12-04     4.0
2016-12-10    10.0
dtype: float64




 

 

 

  (3) DataFrame 값에 선형으로 비례하는 방식으로 결측값 보간
      (interpolate DataFrame missing values linearly)

 



In [15]: df = DataFrame({'C1': [1, 2, np.nan, np.nan, 5],
    ...: 'C2': [6, 8, 10, np.nan, 20]})
    ...:


In [16]: df
Out[16]:
    C1    C2
0  1.0   6.0
1  2.0   8.0
NaN  10.0
NaN   NaN
4  5.0  20.0



In [17]: df_intp_values = df.interpolate(method='values')

In [18]: df_intp_values
Out[18]:
    C1    C2
0  1.0   6.0
1  2.0   8.0
3.0  10.0
4.0  15.0
4  5.0  20.0





# the same with : df.interpolate(method='values') = df.interpolate()
In [19]: df.interpolate() # by default : method='values'
Out[19]:
    C1    C2
0  1.0   6.0
1  2.0   8.0
3.0  10.0
4.0  15.0
4  5.0  20.0


 

 

 

 (4) 결측값 보간 개수 제한하기 (limit the number of consecutive interpolation) : limit

 

연속적으로 결측값을 보간하는 개수를 'limit=1'을 사용해서 제한해보겠습니다.  아래 예시처럼 df.ix[3, 'C1']의 NaN이 보간되지 않고 NaN 그대로 남아있습니다.

 



In [20]: df.interpolate(method='values', limit=1)
Out[20]:
    C1    C2
0  1.0   6.0
1  2.0   8.0
3.0  10.0
NaN  15.0
4  5.0  20.0




 

 

 

limit_direction='backward' 로 설정해주면 보간해주는 방향이 밑에서 위로 올라가면서 해주게 됩니다.

(아무런 설정을 안해주면 default 로 limit_direction='forward' 설정됨.  limit_direction='both' 도 있음)

 



In [29]: df.interpolate(method='values', limit=1, limit_direction='backward')
Out[29]:
    C1    C2
0  1.0   6.0
1  2.0   8.0
NaN  10.0
4.0  15.0
4  5.0  20.0



 

 

 

이상으로 Python pandas 의 interpolate() method를 활용한 결측값 보간법을 마치도록 하겠습니다.

 

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

 

728x90
반응형
Posted by Rfriend
,

지난번 포스팅에서는 Python pandas의 fillna() method를 사용한

 

 - 결측값 여부 확인하기

 - 결측값 채우기, 결측값 대체하기

 

에 대해서 알아보았습니다.

 

이번 포스팅에서는 Python pandas의 dropna() method를 사용해서

 

 - 결측값이 들어있는 행 전체 제거

   (delete row with missing values)

 - 결측값이 들어있는 열 전체를 제거

   (delete column with missing values)

 - 특정 행 또는 열 만을 대상으로 결측값이 들어있으면 제거

   (delete specific row or column with missing values)

 

하는 방법을 소개하겠습니다.

 

관측값이 아주 많고 결측값이 별로 없는 경우에는 결측값이 들어있는 행 전체를 삭제하고 분석을 진행해도 무리가 없고 편리할 수 있습니다.

 

혹은 특정 변수의 결측값 비율이 매우 높고, 결측값을 채워넣을 만한 마땅한 방법이 없는 경우에는 분석의 신뢰성 확보를 위해서 그 변수(행, 칼럼)을 삭제하고 분석을 진행할 필요도 있습니다.

 

이때 dropna() method 를 사용하면 됩니다.

 

 

 

 

먼저, 필요한 모듈을 불러오고, 결측값(None 또는 np.nan)이 들어있는 DataFrame을 만들어보겠습니다.

 

import numpy as np
import pandas as pd


# seeding the random generator for reproducibility
np.random.seed(1004) 

## making a sample DataFrame
df = pd.DataFrame(
    np.random.randn(5, 4), 
    columns=['C1', 'C2', 'C3', 'C4']
)

print(df)
#          C1        C2        C3        C4
# 0  0.594403  0.402609 -0.805162  0.115126
# 1 -0.753065 -0.784118  1.461576  1.576076
# 2 -0.171318 -0.914482  0.860139  0.358802
# 3  1.729657 -0.497648  1.761870  0.169013
# 4 -1.085237 -0.010652  1.115798 -1.264972


## adding the missing values (None or np.nan)
df.loc[[0, 1], 'C1'] = None
df.loc[2, 'C2'] = np.nan

print(df)
#          C1        C2        C3        C4
# 0       NaN  0.402609 -0.805162  0.115126
# 1       NaN -0.784118  1.461576  1.576076
# 2 -0.171318       NaN  0.860139  0.358802
# 3  1.729657 -0.497648  1.761870  0.169013
# 4 -1.085237 -0.010652  1.115798 -1.264972

 

 

 

이제 dropna() method를 사용해서 결측값이 들어있는 행 전체(axis = 0) 삭제, 혹은 결측값이 들어있는 열 전체(axis=1) 삭제해 보겠습니다.

 

  (1) 결측값이 들어있는 행 전체 삭제하기(delete row with NaN) : df.dropna(axis=0)

 

## deleting rows with missing values
df_drop_row = df.dropna(axis=0)

print(df_drop_row)
#          C1        C2        C3        C4
# 3  1.729657 -0.497648  1.761870  0.169013
# 4 -1.085237 -0.010652  1.115798 -1.264972

 

 

 

(2) 결측값이 들어있는 열 전체 삭제하기 (delete column with NaN) : df.dropna(axis=1)

 

print(df)
#          C1        C2        C3        C4
# 0       NaN  0.402609 -0.805162  0.115126
# 1       NaN -0.784118  1.461576  1.576076
# 2 -0.171318       NaN  0.860139  0.358802
# 3  1.729657 -0.497648  1.761870  0.169013
# 4 -1.085237 -0.010652  1.115798 -1.264972


## deleting columns with missing values
df_drop_column = df.dropna(axis=1)
print(df_drop_column)
#          C3        C4
# 0 -0.805162  0.115126
# 1  1.461576  1.576076
# 2  0.860139  0.358802
# 3  1.761870  0.169013
# 4  1.115798 -1.264972

 

 

 

(3) 특정 행 또는 열을 대상으로 결측값이 들어있으면 제거
       (delete specific row or column with missing values) : df[ ].dropna()

 

DataFrame의 행 또는 열을 indexing 한 후에 dropna() method를 적용하면 됩니다.  dropna() 와 dropna(axis=0)은 동일합니다 (즉, axis=0 은 생략 가능).

 

아래에 4가지의 예를 들어보았습니다.  원래의 df DataFrame을 어떻게 indexing 하느냐에 따라 결측값이 들어있는 행과 열이 제거되는지 유심히 살펴보시면 금방 이해가 될거예요.

 

 

[df DataFrame의 칼럼 'C1' 에서 결측값이 있는 행 제거하기 ==> return Series]

print(df)
#          C1        C2        C3        C4
# 0       NaN  0.402609 -0.805162  0.115126
# 1       NaN -0.784118  1.461576  1.576076
# 2 -0.171318       NaN  0.860139  0.358802
# 3  1.729657 -0.497648  1.761870  0.169013
# 4 -1.085237 -0.010652  1.115798 -1.264972


## deleting specific columns with missing values
df['C1'].dropna()
# 2   -0.171318
# 3    1.729657
# 4   -1.085237
# Name: C1, dtype: float64

 

 

[df DataFrame의 칼럼 'C1', 'C2', 'C3' 에서 결측값이 있는 행(axis=0, by default) 제거하기, 열(axis=1) 제거하기 ==> return DataFrame]

print(df[['C1', 'C2', 'C3']])
#          C1        C2        C3
# 0       NaN  0.402609 -0.805162
# 1       NaN -0.784118  1.461576
# 2 -0.171318       NaN  0.860139
# 3  1.729657 -0.497648  1.761870
# 4 -1.085237 -0.010652  1.11579



## dropping rows with missing values, the same with dropna(axis=0)
df[['C1', 'C2', 'C3']].dropna()
#          C1        C2        C3
# 3  1.729657 -0.497648  1.761870
# 4 -1.085237 -0.010652  1.115798


## dropping columns with missing values
df[['C1', 'C2', 'C3']].dropna(axis=1)
#          C3
# 0 -0.805162
# 1  1.461576
# 2  0.860139
# 3  1.761870
# 4  1.115798

 

 

[df DataFrame의 행 2, 4, 그리고 칼럼 'C1', 'C2', 'C3'에서 결측값이 있는 행 제거하기 ==> return DataFrame]

df.loc[[2, 4], ['C1', 'C2', 'C3']]
#          C1        C2        C3
# 2 -0.171318       NaN  0.860139
# 4 -1.085237 -0.010652  1.115798


## droping rows with missing values
df.loc[[2, 4], ['C1', 'C2', 'C3']].dropna(axis=0)
#          C1        C2        C3
# 4 -1.085237 -0.010652  1.115798

 

 

 

마지막으로 첨언하자면, 결측값이 들어있는 행 전체, 혹은 열 전체를 삭제하는 것은 데이터 소실, 혹은 데이터 모집단 왜곡의 위험도 있는 만큼 분석에 영향도를 한번 생각해보고 나서 결정하시면 좋겠습니다.

 

그리고 만약을 대비해서 원본 데이터 (source data)는 그대로 남겨 놓은 상태에서 행 삭제 혹은 열 삭제 후의 DataFrame은 다른 이름으로 copy 해서 사용하실 것을 권합니다. 

 

다음번 포스팅에서는 결측값 보간(interpolation)에 대해서 알아보겠습니다.

 

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

 

 

 

728x90
반응형
Posted by Rfriend
,