[머신러닝] 전처리(Label Encoder / MinMax Scaler / Standard Scaler / Robust Scaler) , 와인 데이터 분석

황성미·2023년 9월 19일
0
post-thumbnail
post-custom-banner

✍🏻 19일 공부 이야기.


전처리에서 많이 사용되는 도구들을 살펴보자. 오늘 공부한 코드는 아래 깃허브에 올려두었다 🤗 https://github.com/castlemi99/ZeroBaseDataSchool/tree/main/Machine%20Learning

Label Encoder

문자형 데이터를 숫자형 데이터로 변환시켜주는 도구

import pandas as pd

df = pd.DataFrame({
    'A': ['a', 'b', 'c', 'a', 'b'],
    'B' : [1,2,3,1,9]    
    })
df

💻 출력

위와 같은 데이터 프레임이 있다. 'A' 컬럼의 데이터 값들을 숫자형으로 바꾸고 싶을 때 Label Encoder를 사용하면 된다.

📌 순서는 fit -> transform -> 데이터프레임에 적용

from sklearn.preprocessing import LabelEncoder

le = LabelEncoder()
le.fit(df['A'])

fit시켜주면 le 학습기에 데이터들이 들어가있다.

# 데이터 프레임에 적용

df['le_A'] = le.transform(df['A']) # array([0, 1, 2, 0, 1])
df

이를 데이터프레임에 적용시키면

문자형이 숫자형으로 바뀐 것을 볼 수 있다.

만약 fittransform을 한 번에 하고 싶다면

le.fit_transform(df['A'])

을 이용하면 된다.


추가적으로

le.transform(['a']) 는 기존의 값이 어떤 값으로 바뀌었는지 살펴볼 수 있다. 이 때 만약 fit되지 않은 값을 넣게 되면(예를 들어 le.transform(['d'])) 에러가 뜬다.

le.inverse_transform(df['le_A'])
transform된 내용을 다시 원상태로 돌려놓을 수도 있다.


Min-Max scaler

주어진 값을 최소값으로 뺀 후 최대값과 최소값의 차이로 이를 나누어 준다.

xx' = xmin(x)max(x)min(x)x - min(x)\over max(x) - min(x)

이 때 xmin(x)x - min(x) 는 최소값을 0으로 만드는 역할을 하며

max(x)min(x)max(x) - min(x) 는 크기를 1로 만들어 최대값을 1로 만드는 역할을 한다.

하는 방식은 위와 같다.

변환기 생성 -> fit -> transform -> 데이터프레임에 적용

from sklearn.preprocessing import MinMaxScaler

mms = MinMaxScaler()
mms.fit(df)

df_mms = mms.transform(df)
df_mms # min-max scaler가 적용된 데이터

# fit과 transform을 한 번에
#mms.fit_transform(df)

💻 출력

똑같이 inverse_transform을 통해 역변환할 수 있으며

각 컬럼의 fit된 값들 또한 확인할 수 있다.


Standard scaler

데이터를 표준정규분포 형태로 만들어준다.

ZZ = XμσX - \mu\over \sigma

from sklearn.preprocessing import StandardScaler

ss = StandardScaler()
ss.fit(df)

df_ss = ss.transform(df)
df_ss

# fit과 transform을 한 번에
#ss.fit_transform(df)

💻 출력


각 컬럼의 fit된 값 역변환

Robust scaler

xiQ2Q3Q1x_i - Q_2\over Q_3 - Q_1 형태로 만들어준다.

이 형태의 의미는 아래와 같다.

xiQ2x_i - Q_2 : 데이터의 중앙값을 0으로 만들고
Q3Q1Q_3 - Q_1 : 데이터의 25% ~ 75% 까지의 데이터의 길이를 1로 보자.


지금까지 공부한 3가지 스케일러를 비교해보자.

from sklearn.preprocessing import MinMaxScaler, StandardScaler, RobustScaler

mm = MinMaxScaler()
ss = StandardScaler()
rs = RobustScaler()

df_scaler = df.copy()

df_scaler['MinMax'] = mm.fit_transform(df)
df_scaler['Standard'] = ss.fit_transform(df)
df_scaler['Robust'] = rs.fit_transform(df)

df_scaler

💻 출력

각 스케일러를 적용한 데이터프레임이다.

이해를 더 쉽게 하기 위해 boxplot을 그려보았다.

위 시각화된 내용을 분석해보면
원본 데이터에 이상치(5)가 존재한 것으로 보인다.

각 스케일러의 특징을 살펴보자면 아래와 같다.

  1. MinMax : 최소값을 0으로 최대값을 1로 만들어준다. 이런 특성 때문에 이상치의 영향을 많이 받는다.

  2. Standard : 평균을 0으로 만들어준다. 이런 특성 떄문에 이상치의 영향을 많이 받는다.

  3. Robust : 중앙값을 0으로 Q3Q1Q_3 - Q_1을 1로 만들어준다. 따라서 위의 두 스케일러보단 이상치의 영향을 덜 받아 데이터의 밀집도가 원 데이터랑 비슷하다는 특징이 있다.

그렇다고 무조건 Robust를 써야한다!! 는 아닐 것이다.
이 또한 데이터의 분포 형태를 보고 데이터 분석가의 몫😊😊



와인 데이터 분석

"레드 와인과 화이트 와인을 구분할 수 있을까?"

간단한 인사이트

데이터는 아래 사이트에서 읽어들여왔다.

https://github.com/PinkWink/ML_tutorial/tree/master/dataset

# 데이터 읽기

import pandas as pd

red_url = 'https://raw.githubusercontent.com/PinkWink/ML_tutorial/master/dataset/winequality-red.csv'
white_url = 'https://raw.githubusercontent.com/PinkWink/ML_tutorial/master/dataset/winequality-white.csv'

red_wine = pd.read_csv(red_url, sep = ';')
white_wine = pd.read_csv(white_url, sep = ';')

두 데이터의 구조가 동일하다. 그러므로 분석을 위해 하나의 데이터프레임으로 만들어주자. 이때, 레드 와인과 화이트 와인을 구분할 수 있는 컬럼을 추가해주어야한다.

# 와인 색상 구분 컬럼
red_wine['color'] = 1
white_wine['color'] = 0

# 두 데이터 합치기
wine = pd.concat([red_wine, white_wine])
wine.info()

레드, 화이트 와인별 등급 분포는 어떻게 되어있을까?

위 차트를 보아, 레드 와인 데이터의 비중이 화이트 와인 데이터의 비중보다 적고
두 와인 모두 5,6등급의 와인 데이터가 많은 것을 알 수 있다.

이제, 레드 와인과 화이트 와인을 분류하는 모델을 만들어보자.


레드/화이트 와인 분류기

X = wine.drop(['color'], axis=1)
y = wine['color'] # 타겟 데이터

# 학습용 / 테스트용 데이터 분리
from sklearn.model_selection import train_test_split
import numpy as np

X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=13)
# 데이터에 무엇이 들어가있고, 각각의 개수가 얼만큼 있는지 확인 가능
np.unique(y_train, return_counts=True) 

타켓 데이터인 color 필드를 제외한 데이터는 X에, 타켓 데이터는 y로 두고 학습용 / 테스트용 데이터를 분리시켜주었다.

지금은 사용하지 않았지만
저번 시간에 타켓 데이터의 비율을 학습용/테스트용 데이터에 고르게 하기 위해 배운 stratify을 사용하는 것이 좋다.

이제 레드 와인과 화이트 와인을 구분하기 위한 분류기를 생성해보자.

# Decision Tree

from sklearn.tree import DecisionTreeClassifier

wine_tree = DecisionTreeClassifier(max_depth=2, random_state=13)
wine_tree.fit(X_train, y_train) # 학습

# Train/Test 데이터에 대한 성능을 평가해보자
from sklearn.metrics import accuracy_score

# 예측
y_pred_tr = wine_tree.predict(X_train) 
y_pred_test = wine_tree.predict(X_test) 

# 성능
accuracy_score(y_train, y_pred_tr), accuracy_score(y_test, y_pred_test)

별다른 전처리 없이도 95%의 좋은 성능을 가진 분류기가 나왔다.

하지만 이번 시간에 배운 전처리 내용을 더 활용해보자.
먼저 말하자면 DecisionTree 모델은 이번에 배운 스케일러를 한다고 성능이 크게 달라지진 않는다. 그렇지만 한 번 느낌만 살짝 맛보자!!

기존 데이터의 분포는 아래와 같다.

fig = go.Figure()
fig.add_trace(go.Box(y = X['fixed acidity'], name = 'fixed acidity'))
fig.add_trace(go.Box(y = X['chlorides'], name = 'chlorides'))
fig.add_trace(go.Box(y = X['quality'], name = 'quality'))

fig.show()

각 컬럼들의 데이터 분포를 보았는데, 컬럼간 데이터의 분포의 격차가 커보이는 경우 학습이 제대로 안 될 수도 있다.(잘 될수도 있고) 그래서 그것을 막고자 스케일러를 하는 것이다.

MinMax Scaler / Standard Scaler

from sklearn.preprocessing import MinMaxScaler, StandardScaler

mms = MinMaxScaler()
ss = StandardScaler()

ss.fit(X)
mms.fit(X)

X_ss = ss.transform(X)
X_mms = mms.transform(X)

X_ss_pd = pd.DataFrame(X_ss, columns = X.columns)
X_mms_pd = pd.DataFrame(X_mms, columns = X.columns)
Standard MinMax

데이터들이 스케일된 것을 볼 수 있다.
이 데이터로 이제 분류기를 학습해보고 성능을 평가해보자.

Standard MinMax

앞서 말한 것처럼 크게 성능이 차이가 나지 않았다.
그래도 다른 데이터에서는 (특히 Cost Function을 최적화할 때) 유효할 수도 있으니 여러 스케일러 중 어떤 것이 효과적인지 살펴볼 필요는 있다.


와인 맛에 대한 이진분류

번외로 모델을 생성할 때 주의해야할 점이 있다.

만약 위 데이터의 quality 컬럼을 이용해 와인을 맛있다맛없다로 분류할 수 있는 분류기를 만들고자 한다고 해보자.

# quality 컬럼을 이진화

wine['taste'] = [1. if grade > 5 else 0. for grade in wine['quality']]

임의로 quality가 5 초과인 데이터들에 대해서는 맛있다(1)를 부여하고 5 이하인 데이터들에 대해서는 맛없다(0)를 부여했다.

위 데이터 프레임 중 타겟 데이터인 taste 필드를 y에 두고 똑같이 Decision Tree를 돌려보면

100% 의 성능이 나온다...!?!


💡 여기서 주의해야할 점.

원본 데이터를 이용해 다른 필드를 생성할 땐, 이용한 원본 데이터 필드가 데이터 분석에 영향을 주게 되므로 해당 필드를 삭제해주어야한다.

quality 필드까지 삭제한 X 데이터에 대해 분류기를 돌리면 70 % 대의 성능을 가진 분류기가 만들어진 것을 볼 수 있다 :)

profile
데이터 분석가(가 되고픈) 황성미입니다!
post-custom-banner

0개의 댓글