[ML] Intro - Wine 품질 예측하기

강주형·2022년 7월 4일
0
post-custom-banner

강의에서는 다루지 않은 데이터 처음부터 혼자 짜보기

지난 학기에 나를 괴롭혔던 Wine 데이터를 활용하기로 했다.

데이터 출처: https://archive.ics.uci.edu/ml/datasets/wine+quality

사전 작업

레드 와인, 화이트 와인으로 분리되어 있음

import pandas as pd

white_wine = pd.read_csv("winequality-white.csv", sep=';')
red_wine = pd.read_csv("winequality-red.csv", sep=';')
display(white_wine.head(3))
display(red_wine.head(3))

두 데이터를 합쳐서 사용하기로 함

wine = pd.concat([white_wine, red_wine])
wine.info()
<class 'pandas.core.frame.DataFrame'>
Int64Index: 6497 entries, 0 to 1598
Data columns (total 12 columns):
 #   Column                Non-Null Count  Dtype  
---  ------                --------------  -----  
 0   fixed acidity         6497 non-null   float64
 1   volatile acidity      6497 non-null   float64
 2   citric acid           6497 non-null   float64
 3   residual sugar        6497 non-null   float64
 4   chlorides             6497 non-null   float64
 5   free sulfur dioxide   6497 non-null   float64
 6   total sulfur dioxide  6497 non-null   float64
 7   density               6497 non-null   float64
 8   pH                    6497 non-null   float64
 9   sulphates             6497 non-null   float64
 10  alcohol               6497 non-null   float64
 11  quality               6497 non-null   int64  
dtypes: float64(11), int64(1)
memory usage: 659.9 KB

quality에 대해서 분류 예측을 하는 것이 목표!
이진 분류로 하기 위해 quality가 6 이상인 것과 미만인 것으로 분류하기로 한다.
binary_quality 함수를 만들고 apply lambda식을 사용해서 우리가 Label로 사용할 target 칼럼을 생성

target의미
1quality가 6 이상인 와인
0quality가 6 미만인 와인
def binary_quality(x):
    target = None
    if x >= 6:
        target = 1
    else:
        target = 0
    return target

wine['target'] = wine['quality'].apply(lambda x : binary_quality(x))
print(wine['target'].value_counts())
1    4113
0    2384
Name: target, dtype: int64

우리가 Label로 사용할 target을 새로운 데이터세트로 분리함
Feature 데이터세트에서는 필요없는 target과 quality 제거

wine_y = wine['target']
wine_X = wine.drop(['target', 'quality'], axis = 1)
display(wine_X.head())


train, test 데이터 분리

train, test 데이터를 분리함
train 데이터는 80%, test 데이터는 20%로 설정
stratify = wine_y로 해서 Label이 균일하게 들어가게 설정했음

from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(wine_X, wine_y, test_size = 0.2, stratify=wine_y, random_state = 12)

데이터 전처리

문자열 칼럼이 없어서 인코딩은 진행하지 않음

모든 칼럼에 대해 MinMax 스케일링을 진행함
반드시 train 데이터에 대해서 fit()을 해야함!

from sklearn.preprocessing import MinMaxScaler

scaler = MinMaxScaler()

scaler.fit(X_train)

X_train = scaler.transform(X_train)
X_test = scaler.transform(X_test)

print(X_train)
[[0.62711864 0.16       0.56       ... 0.33070866 0.20224719 0.29032258]
 [0.30508475 0.232      0.35       ... 0.58267717 0.26404494 0.43548387]
 [0.27118644 0.128      0.32       ... 0.33858268 0.11235955 0.51612903]
 ...
 [0.40677966 0.44       0.17       ... 0.27559055 0.16853933 0.20967742]
 [0.25423729 0.352      0.32       ... 0.41732283 0.15730337 0.25806452]
 [0.27966102 0.096      0.37       ... 0.32283465 0.16853933 0.4516129 ]]

DecisionTree와 GridSearchCV

여러 모델을 적합할건데 아직 각 모델마다 어떤 파라미터를 사용하는지 정확히 숙지를 못해서,
DecisionTree만 그리드 서치를 진행하고, 나머지 모델은 교차 검증만 진행하기로 함

DecisonTree 모델 사용하고, 파라미터는 아래와 같이 돌려봄
교차 검증은 cv = 5 로 설정

  • 'max_depth': [2,3,5,10]
  • 'min_samples_split': [2,3,5]
  • 'min_samples_leaf': [1,5,8]
from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import GridSearchCV

dtc = DecisionTreeClassifier(random_state=12)

parameters = {'max_depth':[2,3,5,10], 'min_samples_split':[2,3,5], 'min_samples_leaf':[1,5,8]}

grid_dtc = GridSearchCV(dtc , param_grid=parameters , scoring='accuracy' , cv=5)

grid_dtc.fit(X_train, y_train)

print('GridSearchCV 최적 하이퍼 파라미터\n',grid_dtc.best_params_)
print()
print('GridSearchCV 최고 정확도: ', round(grid_dtc.best_score_,4))
GridSearchCV 최적 하이퍼 파라미터
 {'max_depth': 10, 'min_samples_leaf': 1, 'min_samples_split': 2}

GridSearchCV 최고 정확도:  0.7437

그외 모델과 교차 검증

다른 모델로는 RandomForest, XGBoost, LogisticRegression 사용
cv = 5 로 교차 검증의 평균 정확도를 구함
XGBoost에서 경고 메시지가 출력되는데 왜 그런지 모르겠음..

import numpy as np
from sklearn.model_selection import cross_val_score
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegression
from xgboost import XGBClassifier

rfc = RandomForestClassifier(random_state=12)
xgb = XGBClassifier(random_state=12)
lrg = LogisticRegression(solver='liblinear', random_state=12)

rfc_cv_scores = cross_val_score(rfc, X_train , y_train , cv=5)
xgb_cv_scores = cross_val_score(xgb, X_train , y_train , cv=5)
lrg_cv_scores = cross_val_score(lrg, X_train , y_train , cv=5)

print("rfc 평균 정확도: ", round(np.mean(rfc_cv_scores), 4))
print("xgb 평균 정확도: ", round(np.mean(xgb_cv_scores), 4))
print("lrg 평균 정확도: ", round(np.mean(lrg_cv_scores), 4))
rfc 평균 정확도:  0.8212
xgb 평균 정확도:  0.8016
lrg 평균 정확도:  0.7368

test 데이터 정확도 확인

RandomForest가 교차 검증 평균 정확도가 가장 높게 나옴!
따라서 최종적으로 test 데이터를 RandomForest 모델로 예측함

from sklearn.metrics import accuracy_score

rfc.fit(X_train , y_train)
pred = rfc.predict(X_test)
accuracy = accuracy_score(y_test, pred)

print(" test 데이터에서의 RandomForestClassifier 정확도:", round(accuracy,4))
 test 데이터에서의 RandomForestClassifier 정확도: 0.8331

test 데이터에 대해 정확도가 약 83.31% 나옴!


전체 코드

import pandas as pd

white_wine = pd.read_csv("winequality-white.csv", sep=';')
red_wine = pd.read_csv("winequality-red.csv", sep=';')
display(white_wine.head(3))
display(red_wine.head(3))

wine = pd.concat([white_wine, red_wine])
wine.info()

def binary_quality(x):
    target = None
    if x >= 6:
        target = 1
    else:
        target = 0
    return target

wine['target'] = wine['quality'].apply(lambda x : binary_quality(x))
print(wine['target'].value_counts())

Name: target, dtype: int64
wine_y = wine['target']
wine_X = wine.drop(['target', 'quality'], axis = 1)
display(wine_X.head())

from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(wine_X, wine_y, test_size = 0.2, stratify=wine_y, random_state = 12)

from sklearn.preprocessing import MinMaxScaler

scaler = MinMaxScaler()

scaler.fit(X_train)

X_train = scaler.transform(X_train)
X_test = scaler.transform(X_test)

print(X_train)

from sklearn.tree import DecisionTreeClassifier
from sklearn.model_selection import GridSearchCV

dtc = DecisionTreeClassifier(random_state=12)

parameters = {'max_depth':[2,3,5,10], 'min_samples_split':[2,3,5], 'min_samples_leaf':[1,5,8]}

grid_dtc = GridSearchCV(dtc , param_grid=parameters , scoring='accuracy' , cv=5)

grid_dtc.fit(X_train, y_train)

print('GridSearchCV 최적 하이퍼 파라미터\n',grid_dtc.best_params_)
print()
print('GridSearchCV 최고 정확도: ', round(grid_dtc.best_score_,4))

import numpy as np
from sklearn.model_selection import cross_val_score
from sklearn.ensemble import RandomForestClassifier
from sklearn.linear_model import LogisticRegression
from xgboost import XGBClassifier

rfc = RandomForestClassifier(random_state=12)
xgb = XGBClassifier(random_state=12)
lrg = LogisticRegression(solver='liblinear', random_state=12)

rfc_cv_scores = cross_val_score(rfc, X_train , y_train , cv=5)
xgb_cv_scores = cross_val_score(xgb, X_train , y_train , cv=5)
lrg_cv_scores = cross_val_score(lrg, X_train , y_train , cv=5)

print("rfc 평균 정확도: ", round(np.mean(rfc_cv_scores), 4))
print("xgb 평균 정확도: ", round(np.mean(xgb_cv_scores), 4))
print("lrg 평균 정확도: ", round(np.mean(lrg_cv_scores), 4))

후기

  1. 문자열 데이터가 없어서 인코딩을 진행하지 않음
  2. 결측치도 없어서 전처리할 것이 많지 않았음
  3. 다음에 할 때는 문자열 칼럼이 있는 데이터로 인코딩도 해보기
  4. 이상치도 확인 후 처리 해보는 게 좋을 듯
  5. 파생 변수 만드는 것도 좀 생각해봐야 할 것 같음
profile
Statistics & Data Science
post-custom-banner

0개의 댓글