소소하지만 소소하지 않은 개발 공부/머신 러닝 교과서

Chapter3 머신러닝 교과서, python

still..epochs 2022. 11. 22. 18:08

 

본 포스팅은 머신러닝 교과서를 참고하여 작성되었습니다.

 

3.1 분류 알고리즘 선택

알고리즘을 훈련하기 위한 다섯 가지 주요 단계

  1. 특성을 선택하고 훈련 샘플을 모은다.
  2. 성능 지표를 선택한다.
  3. 분류 모델의 최적화 알고리즘을 선택한다.
  4. 모델의 성능을 평가한다.
  5. 알고리즘을 튜닝한다.

 

3.2 사이킷런 첫걸음 : 퍼셉트론 훈련

사이킷런 라이브러리를 사용해 퍼셉트론 훈련을 해보자

150개의 꽃 샘플에서 꽃잎 길이와 꽃잎 너비를 특성 행렬 X에 할당하고 꽃 품종에 해당하는 클래스 레이블을 벡터 y에 할당한다.

from sklearn import datasets
import numpy as np

iris = datasets.load_iris()
X = iris.data[:, [2,3]]
y = iris.target
print('클래스 레이블:', np.unique(y))

>> 클래스 레이블: [0 1 2]

*클래스 레이블을 정수로 인코딩하는 것은 대부분 머신 러닝 라이브러리들의 공통된 관례이다.

 

모델 성능 평가를 위한 데이터셋 나누기

from sklearn.model_selection import train_test_split

# stratify 계층화 기능 : 훈련 데이터 셋과 테스트 데이터셋의 클래스 레이블 비율을 입력 데이터셋과 동일하게 만든다.
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size = 0.3, random_state = 1, stratify = y)
# 계층화 확인
print('y의 레이블 카운트:', np.bincount(y))
print('y_train의 레이블 카운트:', np.bincount(y_train))
print('y_test의 레이블 카운트:', np.bincount(y_test))

>> y의 레이블 카운트: [50 50 50]
>> y_train의 레이블 카운트: [35 35 35]
>> y_test의 레이블 카운트: [15 15 15]

* 머신 러닝 알고리즘과 최적화 알고리즘은 최상의 성능을 위해 특성 스케일 조정이 필요하다. 여기서는 사이킷런의 preprocessing 모듈의 StandardScaler 클래스를 사용하여 특성을 표준화한다.

from sklearn.preprocessing import StandardScaler
sc = StandardScaler()
sc.fit(X_train)
X_train_std = sc.transform(X_train)
X_test_std = sc.transform(X_test)

- fit 메서드는 훈련 데이터셋의 각 특성 차원마다 샘플 평균과 표준 편차를 계산한다. transform 메서드를 호출하면 계산된 샘플 평균과 표준 편차를 사용하여 훈련 데이터셋을 표준화한다.

 

이제 훈련 데이터를 표준화한 후 퍼셉트론 모델을 훈련시켜보자.

from sklearn.linear_model import Perceptron

# eta0: 학습률, max_iter : 에포크 횟수
ppn = Perceptron(eta0 = 0.1, random_state = 1)
ppn.fit(X_train_std, y_train)
y_pred = ppn.predict(X_test_std)
print('잘못 분류된 샘플 개수: %d' % (y_test != y_pred).sum())

>> 잘못 분류된 샘플 개수: 1

- 이 퍼셉트론 모델이 45개의 샘플에서 한 개를 잘못 분류한다. 테스트 데이터셋에 대한 분류 오차는 약 0.022 또는 2.2% 이다.

 

 

Note_ 분류 오차 vs 정확도

분류 오차 대신 많은 머신 러닝 기술자는 모델의 분류 정확도(accuracy)를 계산한다. 계산은 다음과 같다

1 - 오차 = 0.978 또는 97.8

분류 오차와 정확도 중 어느 것을 선택해도 괜찮다.

 

사이킷런 라이브러리는 metrics 모듈 아래에 다양한 성능 지표를 구현해 놓았다. 테스트 데이터셋에서 퍼셉트론 분류 정확도는 다음과 같이 계산한다.

from sklearn.metrics import accuracy_score
print('정확도: %.3f' % accuracy_score(y_test, y_pred))

>> 정확도: 0.978


print('정확도: %.3f' % ppn.score(X_test_std, y_test))
>> >> 정확도: 0.978

 

마지막으로 plot_decision_regions 함수를 사용하여 새로운 퍼셉트론 모델의 결정 경계를 그려서 세 개의 붓꽃 샘플을 잘 구분하는지 시각화해보자.

from matplotlib.colors import ListedColormap
import matplotlib.pyplot as plt


def plot_decision_regions(X, y, classifier, test_idx=None, resolution=0.02):

    # 마커와 컬러맵을 설정합니다.
    markers = ('s', 'x', 'o', '^', 'v')
    colors = ('red', 'blue', 'lightgreen', 'gray', 'cyan')
    cmap = ListedColormap(colors[:len(np.unique(y))])

    # 결정 경계를 그립니다.
    x1_min, x1_max = X[:, 0].min() - 1, X[:, 0].max() + 1
    x2_min, x2_max = X[:, 1].min() - 1, X[:, 1].max() + 1
    xx1, xx2 = np.meshgrid(np.arange(x1_min, x1_max, resolution),
                           np.arange(x2_min, x2_max, resolution))
    Z = classifier.predict(np.array([xx1.ravel(), xx2.ravel()]).T)
    Z = Z.reshape(xx1.shape)
    plt.contourf(xx1, xx2, Z, alpha=0.3, cmap=cmap)
    plt.xlim(xx1.min(), xx1.max())
    plt.ylim(xx2.min(), xx2.max())

    for idx, cl in enumerate(np.unique(y)):
        plt.scatter(x=X[y == cl, 0], 
                    y=X[y == cl, 1],
                    alpha=0.8, 
                    c=colors[idx],
                    marker=markers[idx], 
                    label=cl, 
                    edgecolor=None if idx==1 else 'black')

    # 테스트 샘플을 부각하여 그립니다.
    if test_idx:
        # 모든 샘플을 그립니다.
        X_test, y_test = X[test_idx, :], y[test_idx]

        plt.scatter(X_test[:, 0],
                    X_test[:, 1],
                    facecolor='none',
                    edgecolor='black',
                    alpha=1.0,
                    linewidth=1,
                    marker='o',
                    s=100, 
                    label='test set')
                    
    
    X_combined_std = np.vstack((X_train_std, X_test_std))
y_combined = np.hstack((y_train, y_test))
plot_decision_regions(X = X_combined_std,
                        y = y_combined,
                        classifier=ppn,
                        test_idx=range(105,150))
plt.xlabel('petal length [standardized]')
plt.ylabel('petal width [standardized]')
plt.legend(loc='upper left')
plt.tight_layout()
plt.show()

퍼셉트론 모델이 만든 붓꽃 데이터셋의 결정 경계

결과 그래프에서 볼 수 있듯이 세 개의 붓꽃 클래스는 선형 결정 경계로 완벽하게 분류되지 못한다. 2장에서 공부했던 것을 떠올리면 퍼셉트론 알고리즘은 선형적으로 구분되지 않는 데이터셋에는 수렴하지 못한다. 실전에서 보통 퍼셉트론 알고리즘을 추천하지 않는 이유이다.

 

다음 장에서는 클래스가 선형적으로 완벽하게 구분되지 않더라도 최솟값에 수렴하는 좀 더 강력한 선형 분류 모델을 알아보자.