데이터 url

    red: http://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-red.csv
    white: http://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-

 

 

white.csv

- 구분자: ;

- 피처
    fixed acidity
    volatile acidity
    citric acid
    residual sugar
    chlorides
    free sulfur dioxide
    total sulfur dioxide
    density
    pH
    sulphates
    alcohol
    quality

 

 

 

1. 데이터 가져오기

import pandas as pd
red = pd.read_csv('http://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-red.csv',
                 sep=";")
red.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 1599 entries, 0 to 1598
Data columns (total 12 columns):
 #   Column                Non-Null Count  Dtype  
---  ------                --------------  -----  
 0   fixed acidity         1599 non-null   float64
 1   volatile acidity      1599 non-null   float64
 2   citric acid           1599 non-null   float64
 3   residual sugar        1599 non-null   float64
 4   chlorides             1599 non-null   float64
 5   free sulfur dioxide   1599 non-null   float64
 6   total sulfur dioxide  1599 non-null   float64
 7   density               1599 non-null   float64
 8   pH                    1599 non-null   float64
 9   sulphates             1599 non-null   float64
 10  alcohol               1599 non-null   float64
 11  quality               1599 non-null   int64  
dtypes: float64(11), int64(1)
memory usage: 150.0 KB

 

white = pd.read_csv('http://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/winequality-white.csv',
                 sep=";")
white.info()
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 4898 entries, 0 to 4897
Data columns (total 12 columns):
 #   Column                Non-Null Count  Dtype  
---  ------                --------------  -----  
 0   fixed acidity         4898 non-null   float64
 1   volatile acidity      4898 non-null   float64
 2   citric acid           4898 non-null   float64
 3   residual sugar        4898 non-null   float64
 4   chlorides             4898 non-null   float64
 5   free sulfur dioxide   4898 non-null   float64
 6   total sulfur dioxide  4898 non-null   float64
 7   density               4898 non-null   float64
 8   pH                    4898 non-null   float64
 9   sulphates             4898 non-null   float64
 10  alcohol               4898 non-null   float64
 11  quality               4898 non-null   int64  
dtypes: float64(11), int64(1)
memory usage: 459.3 KB

 

 

 

2. 기술통계량 확인

wine.describe()


 

 

 

 

3. 정규화

- 데이터의 값을 0 ~ 1로 정규화

wine_norm = (wine - wine.min()) / (wine.max() - wine.min())
wine_norm.describe()

 

 

 

 

4. 데이터 셔플

#데이터를 랜덤하게 섞기
wine_shuffle = wine_norm.sample(frac=1)
wine_np = wine_shuffle.to_numpy()
print(wine_np[:5])
[[0.26446281 0.06       0.44578313 0.18711656 0.05980066 0.07986111
  0.2764977  0.13668787 0.41860465 0.08988764 0.60869565 0.83333333
  1.        ]
 [0.32231405 0.37333333 0.12650602 0.02453988 0.11295681 0.10763889
  0.29262673 0.16367843 0.42635659 0.12921348 0.27536232 0.33333333
  0.        ]
 [0.24793388 0.20666667 0.20481928 0.10429448 0.01827243 0.12847222
  0.29262673 0.09658762 0.35658915 0.12359551 0.57971014 0.66666667
  1.        ]
 [0.20661157 0.13333333 0.28313253 0.16257669 0.05149502 0.20833333
  0.4078341  0.1698477  0.31007752 0.16292135 0.2173913  0.5
  1.        ]
 [0.29752066 0.18       0.12048193 0.20398773 0.07475083 0.21527778
  0.51382488 0.22691344 0.30232558 0.15730337 0.13043478 0.5
  1.        ]]

 

 

 

 

5. 훈련 데이터와 테스트 데이터 만들기

#80%에 해당하는 인덱스 구하기
train_idx = int(len(wine_np) * 0.8)
#80% 기준으로 훈련 데이터 와 테스트 데이터 분리
train_X, train_Y = wine_np[:train_idx, :-1], wine_np[:train_idx, -1] 
test_X, test_Y = wine_np[train_idx:, :-1], wine_np[train_idx:, -1] 

#타겟을 원핫인코딩을 수행
train_Y = tf.keras.utils.to_categorical(train_Y, num_classes=2)
test_Y = tf.keras.utils.to_categorical(test_Y, num_classes=2)
print(train_Y[0])
[0. 1.]
  • 일반 머신러닝 알고리즘에서는 타겟을 원핫인코딩 하지 않음

 

 

 

6. 분류 모델 생성

- 마지막 층의 units 은 출력하는 데이터의 개수로 회귀는 1 분류는 2 이상
- 분류 문제의 activation 은 softmax를 많이 사용

model = tf.keras.Sequential([
    tf.keras.layers.Dense(units=48, activation='relu', input_shape=(12,)),
    tf.keras.layers.Dense(units=24, activation='relu'),
    tf.keras.layers.Dense(units=12, activation='relu'),
    tf.keras.layers.Dense(units=2, activation='softmax')
])

model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=0.07),
             loss='categorical_crossentropy',
             metrics=['accuracy'])
model.summary()
  • softmax 함수는 자연 로그의 밑인 e의 지수를 사용해 계산한 뒤 모두 더한 값으로 나누는데 이렇게 나온 결과는 총합이 1.0 인 확률값
  • softmax 는 분류 나 RNN 에서 다음 토큰 예측 등 결괏값으로 확률이 필요한 분야에서 사용
  • 이 경우는 [0.97, 0.03]  으로 나오는데 앞이 red 와인일 확률이고 1이 white 와인일 확률
  • 시그모이드 처럼 곡선 함수

 

#소프트맥스 함수

#소프트맥스 함수
import math

x = np.arange(-2, 2, 0.01)
e_x = math.e ** x

plt.plot(x, e_x)
plt.show()
  • entropy: 정보이론에서 정보량을 나타내기 위해 사용하는 단위
  • 확률의 역수에 로그를 취한 값
  • -log확률
  • 확률이 높은 사건일 수 록 정보량이 적다고 판단하기 때문
  • 엔트로피의 기댓값은 엔트로피에 확률을 곱해준 값
  • 엔트로피가 높은 것은 높은 불확실성을 나타냄
  • 분류문제에서 불확실성의 정도는 낮추는 방향으로 학습을 진행
  • 분류 문제에서는 어느 한쪽의 확률이 높은 쪽으로 학습을 진행

 

 

 

7. 훈련

  • 32개씩 가지고 학습
  • 25% 검증 데이터로 만들어서 확인
  • 총 25번 진행
history = model.fit(train_X, train_Y, epochs=25,
                   batch_size=32, validation_split=0.25)

 

 

 

 

8. 모델 평가

model.evaluate(test_X, test_Y)
  • 이진 분류를 할 때 타겟은 2개의 속성으로 만들어져야 하고 출력 층에서 unit의 개수는 2개이고 손실 함수로 categorical_crossentropy를 사용하고 출력 층의 activation 함수는 softmax를 사용
  • 다중 클래스 분류는 출력 층에서 unit 개수만 변경하면 됩니다.

 

 

 

9. 다중 클래스 분류

#타겟으로 사용할 만한 특성 확인

print(wine['quality'].describe())
count    6497.000000
mean        5.818378
std         0.873255
min         3.000000
25%         5.000000
50%         6.000000
75%         6.000000
max         9.000000
Name: quality, dtype: float64

 

 

#샘플의 타겟 비율이 5:1 정도가 넘어가면 샘플링 비율을 조정

print(wine['quality'].value_counts())
quality
6    2836
5    2138
7    1079
4     216
8     193
3      30
9       5
Name: count, dtype: int64

 

 

#6을 기준으로 6보다 작으면 0 6이면 1 7이상이면 2로 구간화

wine.loc[wine['quality'] <= 5, 'new_quality'] = 0
wine.loc[wine['quality'] == 6, 'new_quality'] = 1
wine.loc[wine['quality'] >= 7, 'new_quality'] = 2

print(wine['new_quality'].value_counts())
new_quality
1.0    2836
0.0    2384
2.0    1277
Name: count, dtype: int64

 

 

#불필요한 데이터 제거

del wine['quality']

 

 

#정규화

  • 딥러닝을 할 때는 이 작업을 하지 않아도 되는데 대신에  epoch 를 늘려주던지 아니면 layer을 더 많이 쌓아 해결
wine_backup = wine.copy()

wine_norm = (wine - wine.min()) / (wine.max() - wine.min())
wine_norm['new_quality'] = wine_backup['new_quality']

 

#셔플

  • 데이터를 읽을 때 순서대로 데이터를 읽었기 때문에 셔플을 하지 않으면 샘플링할 때 어느 한 쪽 데이터가 과표집(많이 표집) 될 수 있다.
  • 여론조사는 컨벤션 효과라고 하는 것 때문에 과표집 문제가 많이 발생
wine_shuffle = wine_norm.sample(frac=1)
print(type(wine_shuffle))
wine_np = wine_shuffle.to_numpy()
<class 'pandas.core.frame.DataFrame'>

 

train_idx = int(len(wine_np) * 0.8)
train_X, train_Y = wine_np[:train_idx, :-1], wine_np[:train_idx, -1] 
test_X, test_Y = wine_np[train_idx:, :-1], wine_np[train_idx:, -1]
  • 딥러닝을 이용해서 분류를 할 때는 타겟을 원핫인코딩 하는 경우가 많다.
  • 분류를 할 때는 activation 을 softmax로 설정하는 경우가 많은데 softmax는 각 클래스에 대한 기대값을 확률의 형태로 나타낸다.
  • 출력이 여러 개의 값으로 구성된다.
  • 가장 기대값이 높은 인덱스에 1을 설정하고 나머지는 0으로 설정
train_Y = tf.keras.utils.to_categorical(train_Y, num_classes=3)
test_Y = tf.keras.utils.to_categorical(test_Y, num_classes=3)

 

 

# 분류 모델 생성

  • 마지막 층의 units 은 출력하는 데이터의 개수로 회귀는 1 분류는 2 이상
  • 분류 문제의 activation 은 softmax를 많이 사용
  • 분류를 할 때 3가지 모양을 가져야 하므로 마지막 층의 units 만 3으로 수정
model = tf.keras.Sequential([
    tf.keras.layers.Dense(units=48, activation='relu', input_shape=(12,)),
    tf.keras.layers.Dense(units=24, activation='relu'),
    tf.keras.layers.Dense(units=12, activation='relu'),
    tf.keras.layers.Dense(units=6, activation='relu'),
    tf.keras.layers.Dense(units=3, activation='softmax')
])


model.compile(optimizer=tf.keras.optimizers.Adam(learning_rate=0.003),
             loss='categorical_crossentropy',
             metrics=['accuracy'])
model.summary()
model.fit(train_X, train_Y, epochs=25, batch_size=32, 
         validation_split=0.25)
model.evaluate(test_X, test_Y)