My Data Story

[개요] 머신러닝 프로젝트 절차(4) - 머신러닝 알고리즘을 위한 데이터 준비 본문

Machine Learning/1. 머신러닝 프로젝트 절차

[개요] 머신러닝 프로젝트 절차(4) - 머신러닝 알고리즘을 위한 데이터 준비

Hwasss 2021. 8. 12. 15:07
728x90

◈  '머신러닝 프로젝트 절차' 목차 

1. 머신러닝 프로젝트 절차(1) - 큰 그림 보기

2. 머신러닝 프로젝트 절차(2) - 데이터 샘플링 및 훈련/테스트 세트 만들기

3. 머신러닝 프로젝트 절차(3) - 데이터 이해를 위한 탐색

4. 머신러닝 프로젝트 절차(4) - 머신러닝 알고리즘을 위한 데이터 준비

     머신러닝 알고리즘에 주입하기 위해 Null 처리, 범주형 변수에 대한 수치화, 특성 스케일링 등을 고려하여 데이터를 정제한다.

5. 머신러닝 프로젝트 절차(5) - 모델 훈련 및 검증

6. 머신러닝 프로젝트 절차(6) - 모델 세부 튜닝

7. 머신러닝 프로젝트 절차(7) - 시스템 론칭


데이터 정제 작업은 모델링하는 과정에서 반복적으로 수정 및 구현하는 작업이기 때문에, 이를 함수로 만들어 자동화해두면 좋다. 

데이터 정제 과정은 예측 변수에만 적용하기 위해서 타깃값은 제거하고 진행한다. 

1. 데이터 정제

훈련 데이터에 반영된  Null 값 처리 방식은 테스트 세트와 실제 데이터에도 동일하게 적용할 것이기에 잘 기록해두면 좋다.

 

  • df.dropna()  # Null 값 있는 row 제거
  • df.drop()     # Null 값 있는 column 제거
  • df.fillna(0)   # Null 값 다른 값으로 채우기

새로운 데이터에서 어떤 값이 누락될 지 모르니 모든 수치형 특성에 imputer 적용하는 것이 바람직하다.

from sklearn.impute import SimpleImputer
imputer = SimpleImputer(strategy='median')

# fit() 시, 추정에 필요한 파라미터 값들 인스턴트에 저장 ex. statistics_
imputer.fit(df) 

# imputer 는 각 특성의 중간값을 계산해 statistics_에 저장
print(imuter.statistics_)

# 훈련 데이터의 누락된 값 변환
X = imputer.transform(df)

 

 

※ 사이킷런의 객체 종류

  • 추정기
    - 추정 자체는 fit()에 의해 진행
    - 추정에 필요한 매개변수들은 하이퍼파라미터로 간주되어, 인스턴스에 저장

  • 변환기
    - 데이터 셋을 변환하는 추정기
    - 데이터 셋을 매개변수로 전달받아 transform() 메서드가 수행
    - 모든 변환기는 fit()과 transform() 연달아 호출하는 역할인 fit_transform() 존재 

  • 예측기
    - 일부 추정기는 predict() 에 의해 주어진 데이터셋에 대한 예측 가능
    - 또한 테스트 세트를 활용해 예측의 품질을 측정하는 score()를 갖음

 

2. 텍스트와 범주형 특성 다루기

대부분의 머신러닝 알고리즘은 숫자를 다루므로 텍스트를 숫자로 변환하는 것이 좋다. 

카테고릴 별 이진 특성 생성 시, OneHotEncoder 활용한다.

from sklearn.preprocessing import OneHotEncoder

# 범주형 특성 하나만 따로 가져옴
df_cat = df[['ocean_proximity']]
encoder = OneHotEncoder()
df_encoder = encoder.fit_transform(df_cat)

# scipy 희소 행렬 출력 => 수천 개의 카테고리가 있는 범주형 특성일 경우 효율적
print(df_encoder)

# 밀집된 numpy 배열로 변환
df_encoder.to_array()

 

카테고리 특성이 담을 카테고리 수가 많다면 원-핫 인코딩은 많은 수의 입력 특성을 생성하게 된다.  

이는 훈련을 느리게 하고 성능을 감소시킨다.

이럴 때 각 카테고리를 임베딩 embedding 이라고 부르는 학습 가능한 저차원의 벡터로 바꿀 수 있다.  

훈련하는 동안 각 카테고리의 표현이 학습된다. 이를 표현학습이라 한다. (추후...)

 

cf. 원-핫 인코딩

더보기

대부분의 통계 모델이나 머신러닝 모델에서 범주형 변수는 이진 가변수의 집합으로 변환해야 한다. 

다시 말해, 범주형 변수가 갖는 값의 개수만큼 이진 변수를 만들어야 한다.

 

예를 들어 기후라는 변수의 값이 '해', '구림', '비', '눈' 이렇게 있다면 4개의 이진 가변수를 생성한다.

 

< 범주형 변수에 대한 원-핫 인코딩 처리 전 >

레코드  기후
1
2 구름
3
4

 

< 범주형 변수에 대한 원-핫 인코딩 처리 후 >

레코드 기후_해 기후_구름 기후_비 기후_눈
1 1 0 0 0
2 0 1 0 0
3 0 0 1 0
4 0 0 0 1

 

※ 원-핫 인코딩을 사용할 때 주의할 사항이 있다!

선형 회귀나 로지스틱 회귀에서 원-핫 인코딩은 다중 공선성과 관련된 문제를 일으킨다. 

이런 경우 한 가변수를 생략하는 방법을 활용할 수 있다.

즉 P개의 개별 수준을 갖는 요인 변수에 대해 P-1 개의 열을 갖는 행렬로 표시한다.

절편이 있기 때문에 P-1 개의 이진 변수 값을 정의하고 나면, 나머지 P번째 값을 자동으로 알 수 있게 된다.

 

< 회귀 분석 시, 범주형 변수에 대한 처리  >

레코드 기후_해 기후_구름 기후_비
1 1 0 0
2 0 1 0
3 0 0 1
4 0 0 0

 

그 밖에도 요인 변수를 인코딩하는 데 대비 부호화 시스템이라는 여러 다른 방법이 있다. 

예를 들어, 총합 대비라고도 하는 편차 부호화 방법은 각 수준을 전반적인 평균과 비교한다. 

또 다른 대비 방법은 다항식 부호화이며, 이는 순서가 있는 요인 변수에 적합하다. 

이런 순서가 있는 요인 변수를 제외하면, 데이터 과학자는 일반적으로 기준 코딩이나 원-핫 인코딩 이외에 다른 유형의 코딩을 접할 일이 거의 없다.


 

 

3. 특성 스케일

트리 기반 알고리즘 제외하면, 머신러닝 알고리즘은 입력 숫자 특성들의 스케일의 차이가 크면 제대로 작동하지 않는다. 

 

특히 거리의 영향을 받는 알고리즘은 스케일 조정이 필수이다. 

ex. KNN, 규제 있는 선형 모델(리소, 라소), SVM, 경사 하강법 사용하는 알고리즘, 신경망

 

대부분의 스케일 조정 기법에서 이상치 Outlier 는 변환 효과를 저해하는 요소이기에, 이상치 제거 후 스케일 조정한다.

 

스케일 조정 시 특성 별로 크기를 유사하게 만드는 것도 중요하지만, 모든 특성을 표준화시켜 동일하게 만들 필요는 없다.

예를 들어, 데이터가 거의 한 곳에 집중되어 있는 특성을 표준화시키면 작은 단위의 변화가 큰 차이를 나타내는 것으로 변형시킬 수 있기 때문이다.

 

모든 변환기에서 스케일링 시, 모든 데이터가 아닌 훈련 데이터에 대해서만 fit() 적용 후  훈련 데이터와 테스트 데이터에 모두 transform() 적용한다.

 

(1) min-max 스케일링

정규화라고도 불린다. 

0~1 사이의 범위에 들도록 이동하고 스케일을 조정한다. 

사이킷런에서 MinMaxScaler 변환기 제공한다.

0~1 사이의 범위를 원치 않는다면 feature_range 통해서 범위 조정 가능하다.

 

(2) 표준화

평균을 뺀 후 표준편차로 나눠, 결과 분포의 분산이 1이 되도록 한다.

범위의 상한, 하한이 특정 알고리즘에서 문제가 될 수도 있다. 하지만 이상치 영향을 덜 받는다.

사이킷런에서 StandardScaler 변환기 제공한다. 

 

(3) 고워거리

데이터를 구성하는 변수들에 연속형과 이진형 변수가 섞여 있는 경우, 변수의 데이터 유형에 따라 거리 지표를 다르게 적용하여 스케일 조정할 수 있다. 

 

˙ 수치형 변수나 순서형 요소에서 두 레코드 간의 거리는 차이의 절댓값(맨하탄 거리)로 계산한다.

˙범주형 변수의 경우 두 레코드 사이의 범주가 서로 다르면 거리가 1 이고 범주가 동일하면 거리는 0이다.

 

step1

각 레코드의 변수 i와 j의 모든 쌍에 대해 d(i,j) 를 계산한다.

step2

각 d(i,j)의 크기를 최솟값이 0이고 최댓값이 1이 되도록 스케일을 조정한다.

step3

거리 행렬을 구하기 위해 변수 간에 스케일된 거리를 모둔 더한 후 평균 혹은 가중 평균을 계산한다.

 

아래와 같이 gower 패키지를 통해 고워 거리를 통한 스케일 조정이 가능하다.

#gower 패키지 설치
!pip install gower

#고워 거리 스케일 조정
import gower
gower.gower_matrix(df)

 

 

4. 나만의 변환기

사이킷런이 유용한 변환기를 많이 제공하지만 특별한 정제 작업이나 어떤 특성들을 조합하는 등의 작업을 위해 자신만의 변환기를 만들어야 할 때가 많다. 이런 데이터 준비 단계를 자동화할수록 더 많은 조합을 자동으로 시도해볼 수 있고 최상의 조합을 찾을 가능성을 매우 높여준다. 

 

사이킷런은 덕 타이핑을 지원하므로 fit(), transform(), fit_transform() 메서드를 구현한 파이썬 클래스를 만든다.

˙ TransformerMixin 은 fit_transform() 메서드를 하나 가지고 있다. 
˙ BaseEstimator는 get_params(), set_params() 메서드를 가지고 있다. 
˙ 사이킷런의 파이프라인과 그리드 탐색에 꼭 필요한 메서드이므로  모든 추정기와 변환기는 BaseEstimator를 상속해야 한다. 

 

from sklearn.base import BaseEstimator, TransformerMixin

rooms_ix, bedrooms_ix, population_i, househodls_ix = 3,4,5,6

class CombineAttributeAdder(BaseEstimator, TransformerMixin) :
   def __init__(self, add_bedrooms_per_room = True) :
      self.add_bedrooms_per_room = add_bedrooms_per_room
   def fit(self, X, y=None) :
      return self 
   def transform(self, X) :
      room_per_household = X[:,rooms_ix] / X[:,households_ix]
      population_per_household = X[:,population_ix] / X[:,households_ix]
      if self.add_bedrooms_per_room : 
         bed_rooms_per_room = X[:,bedrooms_ix] / X[:,rooms_ix]
         return np.c_[X, rooms_per_household, population_per_household, bedrooms_per_room]
      else : 
         return np.c_[X, rooms_per_household, population_per_household]
            
  attr_adder = CombineAttributeAdder(add_bedrooms_per_room=False)
  housing_extra_attribs = attr_adder.transform(housing.values)

 

5. 변환 파이프라인

데이터 전처리 과정에서 변환 단계가 많으면 정확한 순서대로 실행되어야 한다. 

사이킷런에서 Pipeline을 통해 데이터 전처리 순서대로 변환기를 호출하도록 할 수 있다.

Pipeline은 연속된 단계를 나타내는 이름/추정기 쌍의 목록을 입력으로 받는다. 

마지막 단계에는 변환기와 추정기를 모두 사용할 수 있고, 그 외에는 모두 변환기여야 한다. 

 

from sklearn.pipeline import Pipeline
from sklearn.preprocessing import StandardScaler

num_pipeline = Pipeline([
      ('imputer', SimpleImputer(strategy='median')),
      ('attribs_adder', CombineAttributeAdder()),
      ('std_scaler', StandardScaler()),
   ])

#housing_num 은 housing 데이터의 연속형 특성만을 추출
housing_num_tr = num_pipeline.fit_transform(housing_num)

 

하나의 변환기로 범주형 특성과 연속형 특성 각각에 적절한 변환을 적용할 수 있도록 만든다. 

 

from sklearn.compose import ColumnTransformer

num_attribs = list(housing_num) #수치형 열 이름 리스트
cat_attribs = ['ocean_proximity'] #범주형 열 이름 리스트 

#각 튜플은 이름, 변환기, 변화기가 적용될 열 이름의 리스트로 이뤄진다.
full_pipeline = ColumnTransformer([
       ('num', num_pipeline, num_attribs),
       ('cat', OneHotEncoder(), cat_attribs)])
       
housing_prepared = full_pipeline.fit_transform(housing)