사이킷런의 ML 알고리즘을 적용하기 전에 데이터에 대해 미리 처리해야 할 기본 사항이 있다.

  • 결손값: NaN, Null 값을 어떻게 처리할지 결정하기
  • 문자열 값: 머신러닝 알고리즘은 문자열 값을 입력 값으로 허용하지 않기에 숫자형으로 변형해야함.

데이터 인코딩

  • 레이블 인코딩(Label Encoding): 카테고리 피처를 코드형 숫자 값으로 변환하는 것
  • 원-핫 인코딩(One-Hot Encoding): 피처 값의 유형에 따라 새로운 피처를 추가해 고유 값에 해당하는 칼럼에만 1을 표시하고 나머지 칼럼에는 0을 표시하는 방식

레이블 인코딩

from sklearn.preprocessing import LabelEncoder

items = ['TV', '냉장고', '전자레인지', '컴퓨터', '선풍기', '선풍기', '믹서', '믹서']

# LabelEncoder를 객체로 생성한 후, fit()과 transform()으로 레이블 인코딩 수행
encoder = LabelEncoder()
encoder.fit(items)
labels = encoder.transform(items)
print(f'인코딩 변환값; {labels}')
print(f'인코딩 클래스: {encoder.classes_}')
print(f'디코딩 원본값: {encoder.inverse_transform([4, 5, 2, 0, 1, 1, 3, 3])}')

인코딩 변환값; [0 1 4 5 3 3 2 2]
인코딩 클래스: ['TV' '냉장고' '믹서' '선풍기' '전자레인지' '컴퓨터']
디코딩 원본값: ['전자레인지' '컴퓨터' '믹서' 'TV' '냉장고' '냉장고' '선풍기' '선풍기']

레이블 인코딩은 간단하게 문자열 값을 숫자형 카테고리 값으로 변환하지만 숫자 값의 크고 작음에 대한 특성때문에 몇몇 ML 알고리즘에는 이를 적용할 경우 예측 성능이 떨어지는 경우가 발생할 수 있다. 즉, 숫자 변환 값은 단순 코드이지 숫자 값에 따른 순서나 중요도로 인식되면 안된다. 그래서 레이블 인코딩은 선형 회귀와 같은 ML 알고리즘에는 적용하지 않아야 한다.
이때 우리가 쓸 수 있는 인코딩 방식이 원-핫 인코딩이다.

원-핫 인코딩(One-Hot Encoding)

원-핫 인코딩을 위해선 두 가지 주의사항이 있다.
1. OneHotEncoder로 변환하기 전에 모든 문자열 값이 숫자형 값으로 변환돼야 한다.
2. 입력 값으로 2차원 데이터가 필요하다.

from sklearn.preprocessing import OneHotEncoder
import numpy as np

items = ['TV', '냉장고', '전자레인지', '컴퓨터', '선풍기', '선풍기', '믹서', '믹서']

# 숫자형 값으로 변환
encoder = LabelEncoder()
encoder.fit(items)
labels = encoder.transform(items)
# 2차원 데이터로 변환
labels = labels.reshape(-1, 1)

oh_encoder = OneHotEncoder()
oh_encoder.fit(labels)
oh_labels = oh_encoder.transform(labels)
print(f'원-핫 인코딩 데이터:\n{oh_labels.toarray()}')
print(f'원-핫 인코딩 데이터 차원:\n{oh_labels.shape}')


판다스에는 원-핫 인코딩을 더 쉽게 지원하는 API get_dummies()가 있다. 이 API를 이용하면 숫자형 값으로 변환 없이 바로 변환이 가능하다.

import pandas as pd

df = pd.DataFrame({'item': ['TV', '냉장고', '전자레인지', '컴퓨터', '선풍기', '선풍기', '믹서', '믹서']})
pd.get_dummies(df)

피처 스케일링과 정규화

  1. 피처 스케일링: 표준화 + 정규화
    • StandardScaler
    • MinMaxScaler
  2. 벡터 정규화: 선형대수 개념의 정규화

StandardScaler

개별 피처를 평균이 0이고 분산이 1인 값으로 변환해준다. 사이킷런에서 구현한 RBF 커널을 이용하는 서포트 벡터 머신, 선형회귀, 로지스틱 회귀는 데이터가 가우시안 분포를 가지고 있다고 가정하고 구현됐기에 사전에 표준화를 적용하는 것은 예측 성능 향상에 중요한 요소가 된다.

from sklearn.datasets import load_iris

iris = load_iris()
iris_data = iris.data
iris_df = pd.DataFrame(data=iris.data, columns=iris.feature_names)

print(f'feature들의 평균값:\n{iris_df.mean()}')
print(f'\nfeature들의 분산값:\n{iris_df.var()}')

from sklearn.preprocessing import StandardScaler

scaler = StandardScaler()
scaler.fit(iris_df)
iris_scaled = scaler.transform(iris_df)

# transform()시 스케일 변환된 데이터 세트가 Numpy ndarray로 반환돼 이를 DataFrame으로 변환
iris_df_scaled = pd.DataFrame(data=iris_scaled, columns=iris.feature_names)
print(f'feature들의 평균값:\n{iris_df_scaled.mean()}')
print(f'\nfeature들의 분산값:\n{iris_df_scaled.var()}')

MinMaxScaler

데이터 값을 0과 1사이의 범위값으로 변환한다. 음수값이 있으면 -1에서 1값으로 변환한다.

from sklearn.preprocessing import MinMaxScaler

scaler = MinMaxScaler()
scaler.fit(iris_df)
iris_scaled = scaler.transform(iris_df)

# transform()시 스케일 변환된 데이터 세트가 Numpy ndarray로 반환돼 이를 DataFrame으로 변환
iris_df_scaled = pd.DataFrame(data=iris_scaled, columns=iris.feature_names)
print(f'feature들의 최솟값:\n{iris_df_scaled.min()}')
print(f'\nfeature들의 최댓값:\n{iris_df_scaled.max()}')

학습 데이터와 테스트 데이터 변환시 유의점

StandardScaler나 MinMaxScaler와 같은 Scaler 객체를 이용해 변환 시 fit(), transform(), fit_transform()메소드를 이용한다.

  • fit()은 데이터 변환을 위한 기준 정보 설정
  • transform()은 설정된 정보를 이용해 데이터를 변환
  • fit_transform()은 두가지를 한번에 적용하는 기능을 수행

학습 데이터 세트로 fit()transform()을 적용하면 테스트 데이터 세트로는 다시 fit()을 수행하지 않고 학습 데이터 세트로 수행한 결과를 이용해 transform() 변환을 적용해야 한다. 만약 테스트 데이터로 다시 새로운 스케일링 기준 정보를 만들게 되면 학습 데이터와 테스트 데이터의 스케일링 기준 정보가 달라져 올바른 예측 결과를 도출하지 못할 수 있다.

# 0-10의 학습 데이터 세트, 0-5의 테스트 데이터 세트 생성
# fit(), transform()은 2차원 이상 데이터만 가능하므로 reshape(-1, 1)로 차원 변경
train_array = np.arange(0, 11).reshape(-1, 1)
test_array = np.arange(0, 6).reshape(-1, 1)

scaler = MinMaxScaler()
scaler.fit(train_array)
train_scaled = scaler.transform(train_array)
print(f'원본 train_array 데이터: {np.round(train_array.reshape(-1), 2)}')
print(f'Scale된 train_array 데이터: {np.round(train_scaled.reshape(-1), 2)}')

scaler.fit(test_array)
test_scaled = scaler.transform(test_array)
print(f'원본 test_array 데이터: {np.round(test_array.reshape(-1), 2)}')
print(f'Scale된 test_array 데이터: {np.round(test_scaled.reshape(-1), 2)}')

scaler.fit(test_array)
test_scaled = scaler.transform(test_array)
print(f'원본 test_array 데이터: {np.round(test_array.reshape(-1), 2)}')
print(f'Scale된 test_array 데이터: {np.round(test_scaled.reshape(-1), 2)}')

Source: 파이썬 머신러닝 완벽 가이드 / 위키북스

profile
데이터 분석 공부용 벨로그

0개의 댓글