2025. 7. 13. 13:58ㆍpython/ML
Data processing은 ML에서 algorithm만큼 중요하다고 한다. 그 이유는 결국 model이 학습하는 양분 자체가 data이기 때문이다.
이번 글에서는 Data를 어떻게 가공할 것이냐에 대해서 알아보고자 한다.
1. Data encoding
1.1 Label Encoding은 문자열(string) 또는 범주형(categorical) 데이터를 숫자형 category 값으로 변환하는 것을 말한다.
가령, “냉장고”, “TV”, “에어컨”과 같은 제품명이 있다고 가정하자. 이러한 값들은 머신러닝 모델에 바로 사용할 수 없기 때문에, 숫자 형태로 변경해 주어야 한다. 이때 Label Encoding 과정을 이용할 수 있다. scikit-learn에는 LabelEncoder라는 클래스가 제공되어 이를 활용할 수 있다.
LabelEncoder를 사용하려면 우선 Encoder 객체를 생성하고, fit() 메서드를 통해 변환에 필요한 매핑 정보를 학습한 뒤, transform() 메서드를 통해 문자열 데이터를 숫자형 category 값으로 변환한다.
from sklearn.preprocessing import LabelEncoder
items = ['TV', '냉장고','전자레인지', '컴퓨터', '선풍기','선풍기','믹서','믹서']
encoder = LabelEncoder()
encoder.fit(items)
labels = encoder.transform(items)
print(f"labels : {labels}")
print(f"encoder_classes : {encoder.classes_}")
print(f"encoder_inverse_transform : {encoder.inverse_transform([4,5,2,0,0,1,1,3])}")
output :
labels : [0 1 4 5 3 3 2 2]
encoder_classes : ['TV' '냉장고' '믹서' '선풍기' '전자레인지' '컴퓨터']
encoder_inverse_transform : ['전자레인지' '컴퓨터' '믹서' 'TV' 'TV' '냉장고' '냉장고' '선풍기']
그러나 Label Encoding은 때때로 문제를 일으킨다. 그 이유는 일부 머신러닝 알고리즘이 변환된 숫자 값에 순서나 크기의 의미가 있다고 잘못 해석할 수 있기 때문이다. 예를 들어, “TV”가 “냉장고”보다 작은 값으로 변환되었다면, 모델이 “TV”가 “냉장고”보다 덜 중요한 값이라고 오해할 가능성이 있다. 이러한 이유로 모델 성능이 저하될 수 있다.
이 문제를 해결하기 위한 방법 중 하나가 바로 One-Hot Encoding 기법이다.
1.2 One-Hot Encoding 이란행 형태로 되어 있는 feature의 고유 값을 열 형태로 차원을 변환한 뒤, 고유 값에 해당하는 column에만 1을 표시하고 나머지 column에는 0을 표시하는 방식이다. 아래 예시를 보자.
| 상품 분류 |
| TV |
| 냉장고 |
| 카메라 |
<행 형태로 되어있는 feature의 고유 값>
| 상품 분류_TV | 상품 분류_냉장고 | 상품 분류_카메라 |
| 1 | 0 | 0 |
| 0 | 1 | 0 |
| 0 | 0 | 1 |
<열 형태로 차원을 변경하여 고유 값에 해당하는 column에만 1을 표시>
이렇게 One-Hot Encoding으로 변환하면, 모델이 각 값에 크기나 순서가 있다고 오해하지 않게 되어, 잘못된 관계 해석으로 인한 성능 저하를 방지할 수 있다.
2. Feature scaling and normalization
서로 다른 변수의 값을 일정한 수준으로 맞춰주는 과정을 scaling이라고 한다. 여기에는 normalization과 standardization이 있다.
우선, Standardization이란 데이터의 feature를 X라고 할 때, N(0,1)을 따르도록 값을 조정하는 과정을 의미한다.
이를 위해, xi_new = (xi - mean(x)) / sigma(x)을 수행한다.
다음으로, normalization이란 서로 다른 feature의 크기를 통일하기 위해 크기를 변환해 주는 개념이라고 한다. 예를 들어, A feature는 단위가 km이고 B feature는 단위가 cm일 때 각각의 값들을 0~1 사이로 만들어주는 작업을 뜻한다.
이를 위해, xi_new = (xi - min(x)) / (max(x) - min(x)) 과정을 수행한다.
정규화 전 :
| sample | x | y | z |
| A | 3 | 4 | 5 |
| B | 30 | 40 | 50 |
정규화 후 :
| sample | x | y | z |
| A | 0 | 0 | 0 |
| B | 1 | 1 | 1 |
scikitlearn에서는 vector normalization을 제공한다. 따라서, 이 과정은 다음과 같은 공식을 따른다.
xi_new = xi / (root(xi^2 + yi^2 + zi^2))
정규화 전:
| sample | x | y | z |
| A | 3 | 4 | 5 |
| B | 30 | 40 | 50 |
정규화 후:
| sample | x | y | z |
| A | 0.424 | 0.566 | 0.707 |
| B | 0.424 | 0.566 | 0.707 |
3. Scikitlearn의 StandardScaler
Scikitlearn의 StandardScaler는 standardization을 쉽게 지원하기 위한 클래스다. 개별 feature 값들을 ~N(0,1)로 만들어준다.
# StandardScaler
from sklearn.datasets import load_iris
from sklearn.preprocessing import StandardScaler
import pandas as pd
import numpy as np
iris = load_iris()
iris_data = iris.data
iris_df = pd.DataFrame(data = iris_data, columns = iris.feature_names)
print(f"iris_df_mean : {iris_df.mean()}")
print(f"iris_df_var : {iris_df.var()}")
scaler = StandardScaler()
scaler.fit(iris_df)
iris_scaled = scaler.transform(iris_df)
iris_scaled_df = pd.DataFrame(data = iris_scaled, columns = iris.feature_names)
print(f"scaled_mean : {iris_scaled_df.mean()}")
print(f"scaled_var : {iris_scaled_df.var()}")
output :
iris_df_mean : sepal length (cm) 5.843333
sepal width (cm) 3.057333
petal length (cm) 3.758000
petal width (cm) 1.199333
dtype: float64
iris_df_var : sepal length (cm) 0.685694
sepal width (cm) 0.189979
petal length (cm) 3.116278
petal width (cm) 0.581006
dtype: float64
scaled_mean : 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
scaled_var : sepal length (cm) 1.006711
sepal width (cm) 1.006711
petal length (cm) 1.006711
petal width (cm) 1.006711
dtype: float64
4. Scikitlearn의 MinMaxScaler
Scikitlearn의 MinMaxScaler는 데이터값을 0에서 1 사이의 범위 값으로 변환해 준다.
# MinMaxScaler
from sklearn.preprocessing import MinMaxScaler
scaler = MinMaxScaler()
scaler.fit(iris_df)
iris_scaled = scaler.transform(iris_df)
iris_scaled_df = pd.DataFrame(data = iris_scaled, columns = iris.feature_names)
print(f"iris_scaled_df.min : {iris_scaled_df.min()}")
print(f"iris_scaled_df.max : {iris_scaled_df.max()}")
output :
iris_scaled_df.min : sepal length (cm) 0.0
sepal width (cm) 0.0
petal length (cm) 0.0
petal width (cm) 0.0
dtype: float64
iris_scaled_df.max : sepal length (cm) 1.0
sepal width (cm) 1.0
petal length (cm) 1.0
petal width (cm) 1.0
dtype: float64
5. 유의사항
학습 데이터와 테스트 데이터의 scaling을 할 때, fit과 transform을 해준다는 것을 위의 예제들을 통해 알 수 있었다.
그런데 fit 과정을 학습 데이터와 테스트 데이터에 각각 적용하게 되면, scaling의 기준이 달라 scaling이 제대로 되지 않는다. 예를 들어, train data는 0~10까지 있다고 가정하고, test data는 0~5까지 있다고 가정하자. 이때, MinMaxScaler로 각각을 fit 시키면 train data의 10과 test data의 5는 똑같은 값인 1을 가진다. 이렇게 되면 학습에 문제가 생겨 모델 성능 저하로 이어질 수 있다. 따라서, train data에 fit을 시킨 객체를 그대로 test data에 fit 대신 transform을 적용해서 사용해야 한다.
'python > ML' 카테고리의 다른 글
| [ML_6] Prediction of pima diabetes using Scikitlearn (0) | 2025.07.17 |
|---|---|
| [ML_5] Prediction of Titanic survival by Scikitlearn (0) | 2025.07.15 |
| [ML_3] cross_validation (0) | 2025.07.12 |
| [ML_2] Let's convert pd.Dataframe to train_test dataset. (1) | 2025.07.10 |
| [ML_1] Let's make iris classification model by Scikitlearn (0) | 2025.07.09 |