hyeonzzz's Tech Blog

[파머완 2장] 5. 데이터 전처리 본문

Machine Learning

[파머완 2장] 5. 데이터 전처리

hyeonzzz 2024. 1. 9. 21:24

2. 사이킷런으로 시작하는 머신러닝 - 데이터 전처리

데이터에 미리 처리해야 할 기본사항

  • 결손값 NaN, Null 값은 허용되지 않는다 -> 고정된 다른 값으로 변환해야 한다
  • 문자열 값은 인코딩돼서 숫자형으로 변환해야 한다

데이터 인코딩

Label encoding

: 문자열 값 -> 숫자형 카테고리 값

TV : 1, 냉장고 : 2, 전자레인지 : 3, 컴퓨터 : 4, 선풍기 : 5, 믹서 : 6

 

from sklearn.preprocessing import LabelEncoder

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

# LabelEncoder를 객체로 생성한 후 , fit( ) 과 transform( ) 으로 label 인코딩 수행. 
encoder = LabelEncoder()
encoder.fit(items) #객체에 데이터를 피팅
labels = encoder.transform(items) #데이터를 숫자로 변환
print('인코딩 변환값:',labels)
인코딩 변환값: [0 1 4 5 3 3 2 2]

 

  • classes_ 속성값으로 어떤 숫자 값으로 인코딩됐는지 확인할 수 있다
  • inverse_transform( )을 통해 인코딩된 값을 다시 디코딩할 수 있다

 

Label encoding의 문제점

  • 큰 숫자를 중요도 높게 보고 가중치가 더 부여될 수 있다
  • 따라서 선형 회귀와 같은 ML 알고리즘에는 적용하지 않아야 한다
  • 트리 계열의 ML 알고리즘에는 적용 가능하다

이를 해결한 것이 원-핫 인코딩!!

 

One-Hot Encoding

: 행 형태를 열 형태로 변환한 뒤, 해당 칼럼에만 1을 표시하고 나머지 칼럼에는 0을 표시

 

from sklearn.preprocessing import OneHotEncoder
import numpy as np

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

# 2차원 ndarray로 변환합니다. 
items = np.array(items).reshape(-1, 1)

# 원-핫 인코딩을 적용합니다. 
oh_encoder = OneHotEncoder()
oh_encoder.fit(items)
oh_labels = oh_encoder.transform(items)

# OneHotEncoder로 변환한 결과는 희소행렬이므로 toarray()를 이용해 밀집 행렬로 변환. 
print('원-핫 인코딩 데이터')
print(oh_labels.toarray())
print('원-핫 인코딩 데이터 차원')
print(oh_labels.shape)
원-핫 인코딩 데이터
[[1. 0. 0. 0. 0. 0.]
 [0. 1. 0. 0. 0. 0.]
 [0. 0. 0. 0. 1. 0.]
 [0. 0. 0. 0. 0. 1.]
 [0. 0. 0. 1. 0. 0.]
 [0. 0. 0. 1. 0. 0.]
 [0. 0. 1. 0. 0. 0.]
 [0. 0. 1. 0. 0. 0.]]
원-핫 인코딩 데이터 차원
(8, 6)

희소행렬 -> 밀집행렬

 

희소행렬 : 대부분의 원소가 0인 행렬

  • 대부분의 데이터가 유용한 값이 아니다
  • non-zero 원소들만 저장
  • 메모리를 효율적으로 사용

밀집행렬 : 대부분의 원소가 0이 아닌 값으로 채워진 행렬

  • 대부분의 데이터가 유용한 값이다
  • 각 행과 열에 대부분의 원소가 존재
  • 메모리 공간을 많이 차지

get_dummies( )를 이용해 원-핫 인코딩으로 바로 변환할 수 있다!!

 


피처 스케일링과 정규화

feature scaling

: 서로 다른 변수의 값 범위를 일정한 수준으로 맞추는 작업

 

  • 표준화 (Standardization) : feature를 평균이 0이고 분산이 1인 가우시안 정규 분포를 가진 값으로 변환

  • 정규화 (Normalization) : 서로 다른 feature크기를 통일, 즉 똑같은 단위로 변경

※ 사이킷런에서 제공하는 Normalizer 모듈과 차이가 있다

 


사이킷런에서 제공하는 대표적인 피처 스케일링 클래스

1) StandardScaler

  • 표준화 지원 클래스
  • feature를 평균이 0이고 분산이 1인 값으로 변환해줌
  • SVM, Linear Regression, Logistic Regression에서 중요
from sklearn.preprocessing import StandardScaler

# StandardScaler객체 생성
scaler = StandardScaler()
# StandardScaler 로 데이터 셋 변환. fit( ) 과 transform( ) 호출.  
scaler.fit(iris_df)
iris_scaled = scaler.transform(iris_df)

#transform( )시 scale 변환된 데이터 셋이 numpy ndarry로 반환되어 이를 DataFrame으로 변환
iris_df_scaled = pd.DataFrame(data=iris_scaled, columns=iris.feature_names)
print('feature 들의 평균 값')
print(iris_df_scaled.mean())
print('\nfeature 들의 분산 값')
print(iris_df_scaled.var())
feature 들의 평균 값
sepal length (cm)   -1.690315e-15
sepal width (cm)    -1.842970e-15
petal length (cm)   -1.698641e-15
petal width (cm)    -1.409243e-15
dtype: float64

feature 들의 분산 값
sepal length (cm)    1.006711
sepal width (cm)     1.006711
petal length (cm)    1.006711
petal width (cm)     1.006711
dtype: float64

모든 평균이 0에 가깝게, 분산은 1에 가깝게 변환되었다

 

2) MinMaxScaler

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

# MinMaxScaler객체 생성
scaler = MinMaxScaler()
# MinMaxScaler 로 데이터 셋 변환. fit() 과 transform() 호출.  
scaler.fit(iris_df)
iris_scaled = scaler.transform(iris_df)

# transform()시 scale 변환된 데이터 셋이 numpy ndarry로 반환되어 이를 DataFrame으로 변환
iris_df_scaled = pd.DataFrame(data=iris_scaled, columns=iris.feature_names)
print('feature들의 최솟값')
print(iris_df_scaled.min())
print('\nfeature들의 최댓값')
print(iris_df_scaled.max())
feature들의 최솟값
sepal length (cm)    0.0
sepal width (cm)     0.0
petal length (cm)    0.0
petal width (cm)     0.0
dtype: float64

feature들의 최댓값
sepal length (cm)    1.0
sepal width (cm)     1.0
petal length (cm)    1.0
petal width (cm)     1.0
dtype: float64

0에서 1 사이의 값으로 변환되는 스케일링이 적용되었다

 

 


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

  • Scaler 객체를 이용해 train 데이터 세트로 fit( )과 transform( )을 적용할 경우 - test 데이터 세트로 다시 새로운 스케일링 기준 정보를 만들게 되면 train과 test 데이터의 스케일링 기준 정보가 달라지기 때문에 올바른 예측 결과를 도출하지 못할 수 있다
  • 서로 다른 원본값이 동일한 값으로 변환된다. 따라서 test 데이터에 다시 fit( )을 적용하면 안되고 transform( )만으로 변환해야 한다
scaler = MinMaxScaler()
scaler.fit(train_array)
train_scaled = scaler.transform(train_array)
print('원본 train_array 데이터:', np.round(train_array.reshape(-1), 2))
print('Scale된 train_array 데이터:', np.round(train_scaled.reshape(-1), 2))

# test_array에 Scale 변환을 할 때는 반드시 fit()을 호출하지 않고 transform() 만으로 변환해야 함. 
test_scaled = scaler.transform(test_array)
print('\n원본 test_array 데이터:', np.round(test_array.reshape(-1), 2))
print('Scale된 test_array 데이터:', np.round(test_scaled.reshape(-1), 2))
원본 train_array 데이터: [ 0  1  2  3  4  5  6  7  8  9 10]
Scale된 train_array 데이터: [0.  0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1. ]

원본 test_array 데이터: [0 1 2 3 4 5]
Scale된 test_array 데이터: [0.  0.1 0.2 0.3 0.4 0.5]

 

※ fit_transform( )을 사용할 때도 test 데이터에서는 사용하면 안된다!!

※ 가능하면 전체 데이터의 스케일링 변환을 적용한 뒤 train과 test로 분리하는 것이 좋다!