[Python 머신러닝] 02-5 데이터 전처리
데이터 전처리
- 데이터 클렌징
- 결손값 처리(Null/NaN 처리)
- 데이터 인코딩(레이블, 원-핫 인코딩)
- 데이터 스케일링
- 이상치 제거
- Feature 선택, 추출 및 가공
데이터 인코딩
- 머신러닝 알고리즘은 문자열 데이터 속성을 입력 받지 않으며 모든 데이터는 숫자형으로 표현되어야 한다.
문자형 카테고리형 속성은 모두 숫자값으로 변환/인코딩 되어야 한다.
레이블 인코딩(Label encoding)
- LabelEncoder 클래스
- fit()과 transform()을 이용하여 변환
| 상품 분류 | 가격 | —레이블 인코딩 후–> | 상품 분류 | 가격 |
|---|---|---|---|---|
| TV | 1,000,000 | 0 | 1,000,000 | |
| 냉장고 | 1,500,000 | 1 | 1,500,000 | |
| 전자렌지 | 200,000 | 4 | 200,000 | |
| 컴퓨터 | 800,000 | 5 | 800,000 | |
| 선풍기 | 100,000 | 3 | 100,000 | |
| 선풍기 | 100,000 | 3 | 100,000 | |
| 믹서 | 50,000 | 2 | 50,000 | |
| 믹서 | 50,000 | 2 | 50,000 |
[TV, 냉장고, 전자렌지, 컴퓨터, 선풍기, 믹서] —> [0, 1, 4, 5, 3, 2]
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]
-> 사이킷런에서는 학습을 할 때도, 변환을 할 때도 fit() 사용
encoder.fit_transform()으로 fit()과 transform() 같이 수행 가능
print('인코딩 클래스:',encoder.classes_)
인코딩 클래스: ['TV' '냉장고' '믹서' '선풍기' '전자렌지' '컴퓨터']
print('디코딩 원본 값:',encoder.inverse_transform([4, 5, 2, 0, 1, 1, 3, 3]))
디코딩 원본 값: ['전자렌지' '컴퓨터' '믹서' 'TV' '냉장고' '냉장고' '선풍기' '선풍기']
원-핫 인코딩(One-Hot encoding)
- OneHotEncoder 클래스
- fit()과 transform()을 이용하여 변환
- 인자로 2차원 ndarray 입력 필요
Sparse 배열 형태로 변환되므로 toarray()를 적용하여 다시 Dense 형태로 변환되어야 함 - pd.get_dummies(DataFrame)을 이용
- 피처 값의 유형에 따라 새로운 피처를 추가해 고유 값에 해당하는 컬럼에만 1을 표시하고 나머지 컬럼에는 0을 표시하는 방식
| 상품 분류 | –원-핫 인코딩 후-> | 상품분류_TV | 상품분류_냉장고 | 상품분류_믹서 | 상품분류_선풍기 | 상품분류_전자렌지 | 상품분류_컴퓨터 |
|---|---|---|---|---|---|---|---|
| TV | 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 |
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로 변환한 결과는 희소행렬(Sparse Matrix)이므로 toarray()를 이용하여 밀집 행렬(Dense Matrix)로 변환.
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)
import pandas as pd
df = pd.DataFrame({'item':['TV','냉장고','전자렌지','컴퓨터','선풍기','선풍기','믹서','믹서'] })
pd.get_dummies(df)
| item_TV | item_냉장고 | item_믹서 | item_선풍기 | item_전자렌지 | item_컴퓨터 | |
|---|---|---|---|---|---|---|
| 0 | 1 | 0 | 0 | 0 | 0 | 0 |
| 1 | 0 | 1 | 0 | 0 | 0 | 0 |
| 2 | 0 | 0 | 0 | 0 | 1 | 0 |
| 3 | 0 | 0 | 0 | 0 | 0 | 1 |
| 4 | 0 | 0 | 0 | 1 | 0 | 0 |
| 5 | 0 | 0 | 0 | 1 | 0 | 0 |
| 6 | 0 | 0 | 1 | 0 | 0 | 0 |
| 7 | 0 | 0 | 1 | 0 | 0 | 0 |
피처 스케일링과 정규화
- 표준화는 데이터의 피처 각각이 평균이 0이고 분산이 1인 가우시안 정규 분포를 가진 값으로 변환하는 것을 의미한다.
- 정규화는 서로 다른 피처의 크기를 통일하기 위해 크기를 변환해주는 개념이다.
StandardScaler
- 평균이 0이고, 분산이 1인 정규 분포 형태로 변환
from sklearn.datasets import load_iris
import pandas as pd
# 붓꽃 데이터 셋을 로딩하고 DataFrame으로 변환합니다.
iris = load_iris()
iris_data = iris.data
iris_df = pd.DataFrame(data=iris_data, columns=iris.feature_names)
print('feature 들의 평균 값')
print(iris_df.mean())
print('\nfeature 들의 분산 값')
print(iris_df.var())
feature 들의 평균 값
sepal length (cm) 5.843333
sepal width (cm) 3.057333
petal length (cm) 3.758000
petal width (cm) 1.199333
dtype: float64
feature 들의 분산 값
sepal length (cm) 0.685694
sepal width (cm) 0.189979
petal length (cm) 3.116278
petal width (cm) 0.581006
dtype: float64
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
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
-> scaler.fit(iris_df)로 max와 min을 구함
- Scaler를 이용하여 학습 데이터와 테스트 데이터에 fit(), transform(), fit_transform() 적용 시 유의사항.
from sklearn.preprocessing import MinMaxScaler
import numpy as np
# 학습 데이터는 0 부터 10까지, 테스트 데이터는 0 부터 5까지 값을 가지는 데이터 세트로 생성
# Scaler클래스의 fit(), transform()은 2차원 이상 데이터만 가능하므로 reshape(-1, 1)로 차원 변경
train_array = np.arange(0, 11).reshape(-1, 1)
test_array = np.arange(0, 6).reshape(-1, 1)
# 최소값 0, 최대값 1로 변환하는 MinMaxScaler객체 생성
scaler = MinMaxScaler()
# fit()하게 되면 train_array 데이터의 최소값이 0, 최대값이 10으로 설정.
scaler.fit(train_array)
# 1/10 scale로 train_array 데이터 변환함. 원본 10-> 1로 변환됨.
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))
원본 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. ]
# 앞에서 생성한 MinMaxScaler에 test_array를 fit()하게 되면 원본 데이터의 최소값이 0, 최대값이 5으로 설정됨
scaler.fit(test_array)
# 1/5 scale로 test_array 데이터 변환함. 원본 5->1로 변환.
test_scaled = scaler.transform(test_array)
# test_array 변환 출력
print('원본 test_array 데이터:', np.round(test_array.reshape(-1), 2))
print('Scale된 test_array 데이터:', np.round(test_scaled.reshape(-1), 2))
원본 test_array 데이터: [0 1 2 3 4 5]
Scale된 test_array 데이터: [0. 0.2 0.4 0.6 0.8 1. ]
-> 학습할 때의 척도(1/10)와 테스트할 때의 척도(1/5)가 달라서 동일한 데이터 값이 다르게 변환됨
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]
-> train_array의 scale 기준으로 test_array도 scale됨