Deep Learning/딥러닝 텐서플로 교과서

3-1. 머신 러닝 핵심 알고리즘 - 지도학습

이니니 2022. 8. 2. 17:51
본 내용은 도서 '딥러닝 텐서플로 교과서'의 내용을 참고했습니다.
출처 : http://www.yes24.com/Product/Goods/100295267?OzSrank=1

github : https://github.com/gilbutITbook/080263

 

 

1. 지도학습

지도학습 : 정답을 컴퓨터에 미리 알려 주고 데이터를 학습시키는 방법

  • 분류(classification) : 주어진 데이터를 정해진 범주에 따라 분류
  • 회귀(regression) : 데이터들의 특성을 기준으로 연속된 값을 그래프로 표현

 


K-최근접 이웃(K-Nearest Neighbor)

주어진 데이터에 대한 분류를 수행하기 위해 사용한다. 직관적이며 사용하기 쉽고, 훈련 데이터셋을 충분히 확보할 수 있는 환경에서 사용하면 좋다.

 

K-최근접 이웃 : 새로운 입력(분류되지 않은 검증 데이터)을 받았을 때, 기존 클러스터에서 모든 데이터와 인스턴스 기반 거리를 측정한 후 가장 많은 속성을 가진 클러스터에 할당하는 분류 알고리즘

K 값의 선택에 따라 새로운 데이터에 대한 분류 결과가 달라질 수 있음

 

 

[예제 : 붓꽃에 대한 분류]

데이터셋 : https://archive.ics.uci.edu/ml/machine-learning-databases/iris/

 

라이브러리 호출 및 데이터 준비

# 벡터 및 행렬의 연산 처리를 위한 라이브러리
import numpy as np

# 데이터를 차트나 플롯으로 그려 주는 라이브러리
import matplotlib.pyplot as plt

# 데이터 분석 및 조작을 위한 라이브러리
import pandas as pd

# 모델 성능 평가
from sklearn import metrics


# 데이터 셋에 열(column) 이름 할당
names = ['sepal-length', 'sepal-width', 'petal-length', 'petal-width', 'Class']

# 데이터를 판다스 프레임워크에 저장, 경로는 수정
dataset = pd.read_csv('./chap3/data/iris.data', names = names)

 

훈련과 검증 데이터셋 분리

# 모든 행을 사용하지만, 열(컬럼)은 뒤에서 하나를 뺀 값을 가져와서 X에 저장
X = dataset.iloc[:, :-1].values

# 모든 행을 사용하지만 열은 앞에서 다섯 번째 값만 가져와서 y에 저장
y = dataset.iloc[:, 4].values


from sklearn.model_selection import train_test_split

# X, y를 사용하여 훈련과 검증 데이터셋으롭 분리하며, 검증 세트의 비율은 20%만 사용
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2)

from sklearn.preprocessing import StandardScaler

# 특성 스케일링(scaling), 평균이 0, 표준편차가 1이 되도록 변환
s = StandardScaler()

# 훈련 데이터와 검증 데이터를 스케일링 처리
X_train = s.transform(X_train)
X_Test = s.transform(X_test)

 

모델 생성 및 훈련

from sklearn.neighbors import KNeighborsClassifier

# K = 50인 K-최근접 이웃 모델 생성
knn = KNeighborsClassifier(n_neighbors = 50)

# 모델 훈련
knn.fit(X_train, y_train)

 

모델 정확도 측정

from sklearn.metrics import accuracy_score

y_pred = knn.predict(X_test)
prnit("정확도 : {}".format(accuracy_score(y_test, y_pred)))
정확도: 0.9333333333333333

 

위와 같은 결과가 출력된다.

 

최적의 K 찾기

k = 10
acc_array = np.zeros(k)

# K는 1에서 10까지 값을 취함
for k in np.arange(1, k+1, 1):
	# for문을 반복하면서 K값 변경
	classifier = KNeighborsClassifier(n_neighbors = k).fit(X_train, y_train)
    
    y_pred = classifier.predict(X_test)
    acc = metrics.accuracy_score(y_test, y_pred)
    acc_array[k-1] = acc
    
max_acc = np.array(acc_array)
acc_list = list(acc_array)
k = acc_list_index(max_acc)
print("정확도", max_acc, "으로 최적의 k는", k+1, "입니다.")
정확도 1.0 으로 최적의 k는 1 입니다.

위와 같은 결과가 나온다.

 

K가 50일 때는 정확도가 93%였지만, K가 1일 때는 정확도가 100%로 높아졌다. K값에 따라 성능이 달라지므로 초기 설정이 매우 중요하다.

 

 


서포트 벡터 머신(SVM)

주어진 데이터에 대한 분류를 할 때 사용한다. SVM은 분류를 위한 기준선을 정의하는 모델로, 커널만 적절히 선택한다면 정확도가 꽤 좋기 때문에, 정확도를 요구하는 분류 문제에 적합하다. 또한, 텍스트를 분류할 때에도 사용한다.

 

결정 경계 : 데이터를 분류하기 위한 기준선

결정 경계는 데이터가 분류된 클래스에서 최대한 멀리 떨어져 있을 때 성능이 가장 좋다.

마진(margin) : 결정 경계와 서포트 벡터 사이의 거리

서포트 벡터(support vector) : 결정 경계와 가까이 있는 데이터

최적의 결정 경계는 마진을 최대로 해야한다.

 

마진을 최대화 할 때, 이상치를 잘 다루어야 한다.

하드 마진(hard margin) : 이상치를 허용하지 않는 것

소프트 마진(soft margin) : 어느 정도의 이상치들이 마진 안에 포함되는 것을 허용하는 것

위 그림은 하드 마진의 예이다.

 

 

[예제 : 붓꽃에 대한 분류]

 

라이브러리 호출

from sklearn import svm
from sklearn import metrics
from sklearn import datasets
from sklearn import model_selection

import tensorflow as tf
import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3' -

TF_CPP_MIN_LOG_LEVEL이라는 환경 변수를 사용해서 로깅을 제어한다.

  • 0 : 기본값으로, 모든 로그가 표시됨
  • 1 : INFO 로그를 필터링
  • 2 : WARNING 로그를 필터링
  • 3 : ERROR 로그를 추가로 필터링

 

 

iris 데이터를 준비하고 훈련과 검증 데이터셋으로 분리

# 사이킷런에서 제공하는 iris 데이터 호출
iris = datasets.load_iris()

# 데이터셋 분리
X_train, X_test, y_train, y_test = 
	model_selection.train_test_split(iris.data, iris.target, test_siez = 0.6, random_state = 42)

 

SVM 모델에 대한 정확도

# SVM 분류기 제작
svm = svm.SVC(kernel = 'linear', C = 1.0, gamma = 0.5)

# 훈련 데이터를 사용하여 SVM 분류기를 훈련시킴
svm.fit(X_train, y_train)

# 훈련된 모델을 사용하여 검증 데이터에서 예측
predictions = svm.predict(x_test)

score = metrics.accuracy_score(y_test, predictions)
print('정확도 : {0.f}'.format(score))
정확도: 0.988889

 

SVM은 선형 분류와 비선형 분류를 지원한다.

  • 선형 커널(linear kernel) : 선형으로 분류 가능한 데이터에 적용. 선형 커널은 기본 커널 트릭으로 커널 트릭을 사용하지 않음
  • 다항식 커널(polynomial kernel) : 실제로는 특성을 추가하지 않지만, 다항식 특성을 많이 추가한 것과 같은 결과를 얻을 수 있는 방법. 이를 통해 고차원으로 데이터 매핑이 가능함
  • 가우시안 RBF 커널(Gaussian RBF kernel) : 다항식 커널의 확장이다. 다항식 커널과는 달리, 차수에 제한 없이 무한한 확장이 가능하다.

 

위의 SVM 분류기 제작 부분에서 C 값은 오류를 어느 정도 허용할 지 지정하는 파라미터이다. C값이 클 수록 하드 마진이고, 작을수록 소프트 마진이다. 

gamma는 결정 경계를 얼마나 유연하게 가져갈지 결정한다. 이 값이 높으면 훈련 데이터에 많이 의존하여 엄청나게 복잡한 곡선 형태를 띠어 과적합이 발생할 수 있으니 조심하도록 하자.


결정 트리(decision tree)

주어진 데이터에 대한 분류를 할 때 사용한다. 결정 트리는 데이터를 분류하거나 결과 값을 예측하는 분석 방법으로서, 이상치가 많은 값으로 구성된 데이터셋을 다룰 때 사용하기 좋다. 또한, 그 과정이 시각화로 잘 되어있어 유용하다.

 

결정 트리는 데이터를 분류한 후, 각 영역의 순도는 증가, 불순도와 불확실성은 감소하는 방향으로 학습 진행한다.

순도 증가, 불확실성 감소 ☞ 정보획득

 

결정 트리에서 불확실성을 계산하는 방법

  • 엔트로피(entropy) : 확률 변수의 불확실성을 수치로 나타낸 것이다. 높을수록 불확실성이 높다.
  • 지니계수(Gini index) : 불순도를 측정하는 지표로서, 데이터의 통계적 분산 정도를 정량화해서 표현한 값이다.(원소 n개 중에서 임의로 두 개를 추출하였을 경우, 추출된 두 개가 서로 다른 그룹에 속해 있을 확률) 지니계수가 높을수록, 데이터가 분산되어 있다.

 

 

[예제 : 타이타닉 승객의 생존 여부 예측하기]

 

라이브러리 호출 및 데이터 준비

데이터 : https://github.com/gilbutITbook/080263/tree/master/chap3/data/titanic

import pandas as pd

# 판다스를 이용하여 train.csv 파일 로드 후, df에 저장
df = pd.read_csv("./chap3/data/titanic/train.csv", index_col = 'PassengerId')

# 상위 5개 행 출력
print(df.head())

 

데이터 전처리

데이터 분석에 필요한 컬럼만 추출하자

# 승객의 생존 여부를 예측하기 위해 아래와 같은 column 사용
df = df[['Pclass', 'Sex', 'Age', 'SibSp', 'Parch', 'Fare', 'Survived']]

# 성별을 나타내는 'sex'를 0, 1로 변환
df['Sex'] = df['Sex'].map({'male' : 0, 'female' : 1})

# 값이 없는 데이터 전부 삭제
df = df.dropna()

X = df.drop('Survived', axis = 1)

# y값은 예측 label
y = df['Survived']

 

훈련과 검증 데이터 셋으로 분리

from sklearn.model_selection import train_test_split

X_train, X_test, y_train, y_test = train_test_split(X, y, random_state = 1)

 

결정 트리 모델 생성

from sklearn import tree

model = tree.DecisionTreeClassifier()

 

모델 훈련

model.fit(X_train, y_train)

 

모델 예측

y_predict = model.predict(X_test)

from sklearn.metrics import accuracy_score

# 검증 데이터에 대한 예측 결과
accuracy_score(y_test, y_predict)
0.8379888268156425

출력 결과가 83%로 좋은 학습결과를 보여주고 있다.

 

혼동 행렬을 이용한 성능 측정

from sklearn.metrics import confusion_matrix

pd.DataFrame(
	confusion_matrix(y_test, y_predict),
	columns = ['Predicted Not Survival', 'Predicted Survival'],
    index = ['True Not Survival', 'True Survival']
)
  Predicted Not Survival Predicted Survival
True Not Survival 99 13
True Survival 16 51

위는 혼동 행렬에 대한 출력결과이다.

 

혼동 행렬은 알고리즘 성능 평가에 사용된다. 의미는 아래와 같다.

  예측 값
Positive Negative
실제 값 Positive TP FN
Negative FP TN
  • TP (True Positive) : 모델이 1이라고 예측했고, 실제 값도 1인 경우
  • TN (True Negative) : 모델이 0이라고 예측했고, 실제 값도 0인 경우
  • FP (False Positive) : 모델이 1이라고 예측했고, 실제 값이 0인 경우
  • FN (False Negative) : 모델이 0이라고 예측했고, 실제 값은 1인 경우

이들을 가지고 여러 가지 성능 지표로 활용할 수 있다.

 

결정 트리를 확대한 것은 랜덤 포레스트이다.


로지스틱 회귀와 선형 회귀

회귀란, 변수가 두 개 주어졌을 때, 한 변수에서 다른 변수를 예측하거나, 두 변수의 관계를 규명하는데 사용하는 방법이다.

  • 독립 변수(예측 변수) : 영향을 미칠 것으로 예상되는 변수
  • 종속 변수(기준 변수) : 영향을 받을 것으로 예상되는 변수

 

로지스틱 회귀

분석하고자 하는 대상들이 두 집단, 혹은 그 이상으로 나누어질 때, 개별 관측치들이 어느 집단에 분류될 수 있는지 분석하고, 이를 예측하는 모형을 개발하는데 사용되는 통계기법이다. 주어진 데이터에 대한 확신이 없거나, 추가적으로 train dataset을 수집할 수 있는 환경에서 사용하면 좋다.

종속 변수 : 이산형 변수, 모형 탐색 방법 : 최대 우도법, 모형 검정 : X^2 테스트

 

분석 절차는 다음과 같다.

  1. 각 집단에 속하는 확률의 추정치 예측
  2. 분류 기준 값을 설정한 후 특정 범주로 분류

 

 

[예제 : 신규 데이터(숫자) 예측]

 

라이브러리 호출 및 데이터 준비

데이터셋 : 사이킷런에서 제공

%matplotlib inline
from sklearn.datasets import load_digits

digita = load_digits()

# digits 데이터셋의 형태이다. 이미지 = 179개, 8 x 8 이미지의 64차원
print("Image Data Shape", digits.data.shape)

# 레이블 이미지 1797개
print("Label Data Shape", digits.target_shape)
Image Data Shape (1797, 64)
Label Data Shape (1797,)

 

digits 데이터셋의 시각화

import numpy as np
import matplotlib.pyplot as plt

plt.figure(figsize = (20, 4))

# 이미지 5개만 확인
for index, (image, label) in enumerate(zip(digits.data[0:5], digits.target[0:5])):
	plt.subplot(1, 5, index + 1)
    plt.imshow(np.reshape(image, (8, 8)), cmap = plt.cm.gray)
    plt.title("Training : %i \n" % label, fontsize = 20)

 

훈련과 검증 데이터셋 분리 및 로지스틱 회귀 모델 생성

from sklearn.model_selection import train_test_split

x_train, x_test, y_train, y_test = train_test_split(digits.data, digits.target, 
                      						test_size = 0.5, random_state = 0)

from sklearn.linear_model import LogisticRegression

# 로지스틱 회귀 모델의 인스턴스 생성
logisticRegr = LogisticRegression()

# 모델 훈련
logisticRegr.fit(x_train, y_train)

 

일부 데이터를 사용한 모델 예측

# 새로운 이미지에 대한 예측 결과 출력(넘파이 형태)
logisticRegr.predict(x_test[0].reshape(1, -1))

# 이미지 10개에 대한 예측 출력(배열)
logisticRegr.predict(x_test[0:10])

 

전체 데이터를 사용한 모델 예측

# 전체 데이터셋에 대한 예측
predictions = logisticRegr.predict(x_test)

# 스코어 메서드를 사용한 성능 측정
score = logisticRegr.score(x_test, y_test)
print(score)
0.9511111111111111

 

혼동 행렬 시각화

import numpy as np
import seaborn as sns
from sklearn import metrics

# 혼동 행렬
cm  metrics.confusion_matrix(y_test, predictions)
plt.figure(figsize = (9, 9))

# heatmap으로 표현
sns.heatmap(cm, annot = True, fmt = ".3f", linewidths = .5, square = True, cmap = 'Blues_r')
plt.ylabel('Actual label')
plt.xlabel('Predicted label')
all_sample_title = 'Accuracy Score : {0}'.format(score)
plt.title(all_sample_title, size = 15)
plt.show()

 

 

선형 회귀

독립 변수 x를 사용하여, 종속 변수 y의 움직임을 예측하고 설명하는데 사용한다. 이 두 변수가 선형 관계를 가질 때 사용하면 유용하다. 또한, 독립 변수가 변경되었을 때, 종속 변수를 추정하는데 유용하다. 독립 변수는 여러개 일 수 있다.

 

로지스틱 회귀와 선형 회귀의 차이점은 아래와 같다.

 

 

[예제 : 날씨 예측]

데이터셋 : 캐글에서 제공하는 날씨 데이터셋 이용(https://www.kaggle.com/akdagmelih/rain-prediction-logistic-regression-example/data?select=weatherAUS.csv)

 

라이브러리 호출

import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as seaborninstance
from sklearn.model_selection import train_test_split
from sklearn.linear_model import LinearRegression
from sklearn import metrics
%matplotlib inline

 

데이터셋 불러오기

dataset = pd.read_csv('./chap3/data/weather.csv')

 

데이터 간 관계를 시각화로 표현

datasets.plot(x='MinTemp', y='MaxTemp', style = 'o')
plt.title('MinTemp vs MaxTemp')
plt.xlabel('MinTemp')
plt.ylable('MaxTemp')
plt.show()

 

 

데이터를 독립 변수와 종속 변수로 분리하고 선형 회귀 모델 생성

X = dataset['MinTemp'].values.reshape(-1, 1)
y = dataset['MaxTemp'].values.reshape(-1, 1)

# 데이터셋 분할
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.2)

# 선형 회귀 클래스 가져오기
regressor = LinearRegression()

# 모델 훈련
regressor.fit(X_train, y_train)

 

회귀 모델에 대한 예측

y_pred = regressor.predict(X_test)
df = pd.DataFrame({'Actual' : y_test.flatten(), 'Predicted' : y_pred.flatten()})
df

 

검증 데이터셋을 사용한 회귀선 표현

plt.scatter(X_test, y_test, color = 'gray')
plt.plot(X_test, y_pred, color = 'red', linewidth = 2)
plt.show()

 

선형 회귀 모델 평가

print('평균제곱법:', metrics.mean_squared_error(y_test, y_pred))
print('루트 평균제곱법:', np.sqrt(metrics.mean_squared_error(y_test, y_pred)))
평균제곱법: 17.011877668640622
루트 평균제곱법: 4.124545753006096