7 분 소요

원본 사이트: https://scikit-learn.org/stable/tutorial/basic/tutorial.html


scikit-learn으로 배우는 머신러닝의 개요

이 문서는 scikit-learn의 전반에 걸쳐 머신러닝의 용어를 소개하고 학습의 예시를 제공합니다.

머신러닝: 문제 설정하기

일반적으로 학습 문제는 train set 라 불리는 n 개의 데이터 샘플 집합으로 학습한 후 알려지지 않은 데이터의 특성을 예측하려고 시도합니다. 만약, 각 데이터 샘플의 특성feature이 여러 개 있다면 이를 다차원 항목 (aka. 다변수 데이터)라고 합니다.

ex) 붓꽃의 한 샘플에는 꽃잎 길이, 꽃잎 너비, 꽃받침 길이 그리고 꽃받침 너비 등의 특성이 있으므로 다변수 데이터입니다.

학습은 여러 개의 범주로 나뉩니다:

  • 지도 학습supervised learning에는 우리가 예측하고자 하는 레이블label이라는 추가적인 특성이 포함됩니다. 이 문제는 다음 중 하나일 수 있습니다. (scikit-learn supervised learning page)

  • 분류classification: 각 샘플은 두 개 이상의 레이블 중 하나에 속합니다. 그리고, 분류의 목적은 이미 레이블이 지정된 과거의 데이터를 기반으로 아직 레이블이 지정되지 않은 새로운 데이터의 레이블을 예측하는 방법을 배우는 것입니다. 분류 문제의 예로는 MNIST 같은 필기 숫자 인식이 있으며, 입력으로 들어온 각 벡터를 유한한 수의 이산 범주 중 하나로 할당하는 것입니다. MNIST 같은 필기 숫자 인식은 분류 문제의 대표적인 예이며, 입력으로 들어온 각 벡터를 유한한 수의 이산적인 레이블 중 하나로 할당하는 것입니다.

  • 회귀regression: 원하는 출력이 연속적인 변수로 구성된 경우를 회귀라고 합니다. 회귀 문제의 예는 연어의 나이와 무게를 기반으로 연어의 길이를 예측하는 것입니다.

  • 비지도 학습unsupervised learning은 학습 데이터에 대응하는 레이블이 없이 입력 벡터 x 세트로만 구성되어 있습니다. 비지도 학습의 목표는 데이터 내에서 군집clustering이라고 하는 그룹을 발견하거나 밀도 추정을 통해 입력 공간 내의 데이터의 분포를 결정하는 것일 수 있습니다. 그리고, 시각화를 위해서 고차원의 데이터를 2차원 또는 3차원으로 축소하는 것일 수 있습니다.(scikit-learn unsupervised learning page)

훈련 세트와 테스트 세트
머신러닝은 데이터 세트의 일부 속성을 학습한 다음 다른 데이터 세트에 대해 해당 속성을 테스트(예측)하는 것입니다. 머신러닝의 일반적인 관행은 데이터 세트를 둘로 분할하여 알고리즘을 평가하는 것입니다. 우리는 그중 하나를 훈련 세트training set, 다른 하나를 테스트 세트testing set이라고 부릅니다. 이들은 각각 모델을 훈련시키고 모델을 테스트합니다.

예시 데이터셋 불러오기

scikit-learn은 분류를 위한 iris와 digits 데이터 세트와 회귀를 위한 diabetes 데이터 세트를 제공합니다.

다음으로, 개인의 shell로 Python 인터프리터를 시작하고 irisdigits 데이터 세트를 불러옵니다.

from sklearn import datasets    # sklearn 라이브러리의 datasets 모듈을 로드합니다.
iris = datasets.load_iris()     # iris 변수에 iris 데이터 세트를 저장합니다.
digits = datasets.load_digits() # digits 변수에 digits 데이터 세트를 저장합니다.

데이터 세트는 모든 데이터와 데이터에 대한 메타데이터를 포함하는 Bunch 객체(딕셔너리와 유사한 객체)입니다. 이 데이터는 (n_samples, n_features) 크기의 배열인 .data 멤버에 저장됩니다. 지도학습의 경우, 한 개 이상의 반응 변수(출력, 타깃)가 .target 멤버에 저장됩니다. 다양한 데이터 세트의 자세한 사항은 전용 문서에서 찾을 수 있습니다.

예를 들어, digits 데이터 세트의 경우 digits.data는 각 digits 샘플을 분류하는 데 사용할 수 있는 특성에 접근할 수 있게 해줍니다.

print(digits.data)
[[ 0.  0.  5. ...  0.  0.  0.]
 [ 0.  0.  0. ... 10.  0.  0.]
 [ 0.  0.  0. ... 16.  9.  0.]
 ...
 [ 0.  0.  1. ...  6.  0.  0.]
 [ 0.  0.  2. ... 12.  0.  0.]
 [ 0.  0. 10. ... 12.  1.  0.]]

그리고 digits.target은 digit 데이터 세트에 대한 정답 레이블을 제공합니다. 즉, 학습하려는 각 숫자 이미지에 해당하는 숫자입니다.

digits.target   # 첫 번째 숫자는 0, 두 번째 숫자는 1을 의미합니다.
array([0, 1, 2, ..., 8, 9, 8])
데이터 세트의 차원
데이터는 항상 (샘플의 갯수, 특성의 갯수)의 2차원 배열이지만, 원래 데이터는 차원이 다를 수 있습니다. digits의 경우 각 원래 데이터는 (8, 8)인 이미지이고 이렇게 접근할 수 있습니다:

>>> digits.images[0]

array([[ 0.,  0.,  5., 13.,  9.,  1.,  0.,  0.],

       [ 0.,  0., 13., 15., 10., 15.,  5.,  0.],
    
       [ 0.,  3., 15.,  2.,  0., 11.,  8.,  0.],
    
       [ 0.,  4., 12.,  0.,  0.,  8.,  8.,  0.],
    
       [ 0.,  5.,  8.,  0.,  0.,  9.,  8.,  0.],
    
       [ 0.,  4., 11.,  0.,  1., 12.,  7.,  0.],
    
       [ 0.,  2., 14.,  5., 10., 12.,  0.,  0.],
    
       [ 0.,  0.,  6., 13., 10.,  0.,  0.,  0.]])

이 데이터 세트의 간단한 예는 원래 문제로부터 scikit-learn에서 사용할 데이터를 형성하기까지의 방법을 보여줍니다.

외부 데이터 세트 불러오기
외부 데이터 세트를 불러오려면, 외부 데이터 세트 불러오기를 참조해주세요.

학습과 예측

digits 데이터 세트의 목표는 주어진 이미지를 올바른 숫자로 예측하는 것입니다. 새로운 데이터의 클래스를 예측할 수 있는 추정기를 학습하도록 샘플이 주어지는데 각 샘플들은 10개의 클래스(0~9) 중 하나에 속한다.

scikit-learn에서 분류를 위한 추정기는 fit(X, y)predict(T) 메서드를 구현하는 Python 객체입니다.

sklearn.svm.SVC 클래스는 support vector classification을 구현한 추정기입니다. 추정기의 생성자는 모델의 매개변수를 인수로 취합니다.

지금은 추정기를 블랙 박스로 간주합니다.

from sklearn import svm
clf = svm.SVC(gamma=0.001, C=100.)
모델의 파라미터 선택하기
이 예시에서는, gamma의 값을 기본으로 설정했습니다. 이 파라미터들의 최적의 값을 찾기 위해서는 그리드 서치교차 검증 같은 도구들을 사용할 수 있습니다.

clf(분류기용) 추정기 객체가 먼저 모델에 적합합니다. 즉, 모델로부터 학습을 해야 합니다. 이것은 훈련 세트를 fit 메소드에 전달하여 수행됩니다. 훈련 세트의 경우 예측에 사용할 마지막 이미지를 제외하고 데이터 세트의 모든 이미지를 사용합니다. [:-1] Python 구문을 사용하여 훈련 세트를 선택합니다. 이는 digits.data에서 마지막 항목을 제외한 모든 항목을 포함하는 새 배열을 생성합니다.

clf.fit(digits.data[:-1], digits.target[:-1])
SVC(C=100.0, gamma=0.001)

이제 새로운 값을 예측할 수 있습니다. 이 경우, digits.data의 마지막 이미지를 예측할 수 있습니다. 예측을 통해 마지막 이미지와 가장 일치하는 훈련 세트의 이미지를 결정할 수 있습니다.

clf.predict(digits.data[-1:])
array([8])

대응하는 이미지:

digit_data.png

보시다시피 어려운 작업입니다. 이미지의 해상도도 좋지 않습니다. 분류기에 동의하시나요?

이 분류 문제의 완전한 예는 다음을 통해 실행하고 공부할 수 있습니다: 필기 숫자 인식

관례

scikit-learn 추정기는 더 좋은 예측을 만들기위해 특정 규칙을 따릅니다. 이는 일반 용어 및 API 요소 용어집에 자세히 설명되어 있습니다.

타입 캐스팅

특별히 지정하지 않는 한 입력의 데이터 타입은 float64로 캐스트됩니다:

import numpy as np
from sklearn import random_projection

rng = np.random.RandomState(0)    # 매 실행마다 같은 값이 나오도록 설정
X = rng.rand(10, 2000)            # (10, 2000) 크기의 랜덤한 값
X = np.array(X, dtype='float32')  # 랜덤한 값이 담겨있는 X를 'float32'타입의 배열로 만듦
X.dtype                           # X의 데이터 타입을 출력
dtype('float32')
transformer = random_projection.GaussianRandomProjection()    # 가우시안 랜덤 투영 변환기로 차원을 줄임
X_new = transformer.fit_transform(X)                          # X를 학습하고 데이터를 변환
X_new.dtype                                                   # X의 데이터 타입을 출력
dtype('float64')

이 예시에는, X의 데이터 타입은 float32이고 fit_transform(X)으로 float64로 캐스팅되었습니다.

회귀 대상은 float64로 캐스트되고 분류 대상은 유지됩니다.

from sklearn import datasets
from sklearn.svm import SVC
iris = datasets.load_iris()     # iris 데이터 세트 불러오기
clf = SVC()                     # Support Vector Classifier 분류기 생성
clf.fit(iris.data, iris.target) # 학습 데이터 세트는 iris.data, 정답 레이블은 iris.target
SVC()
list(clf.predict(iris.data[:3]))    # iris.data의 0~2번째 데이터를 예측
[0, 0, 0]
clf.fit(iris.data, iris.target_names[iris.target])  # 학습 데이터 세트는 iris.data, 정답 레이블은 iris.target에 해당하는 타겟 이름
SVC()
list(clf.predict(iris.data[:3]))    # 정답 레이블이 0~2 값이 아닌 'setosa', 'versicolor', 'virginica' 이므로 해당하는 문자열이 예측값으로 나옴
['setosa', 'setosa', 'setosa']

여기서, 첫번째 predict()iris.target(정수형 배열)을 fit 메서드에 사용했으므로 정수형 배열을 반환했고, 두번째 predict()는 학습을 위해 iris.target_names가 사용되었기 때문에 문자열 배열이 반환되었습니다.

매개변수 재조정 및 업데이트

추정기의 하이퍼파라미터는 set_params() 메서드로 업데이트 할 수 있습니다. fit()을 두 번 이상 호출하면 이전 fit()에서 학습한 내용을 덮어씁니다.

import numpy as np
from sklearn.datasets import load_iris
from sklearn.svm import SVC
X, y = load_iris(return_X_y=True)       # Bunch 객체 대신 (data, target) 값을 반환

clf = SVC()                             # SVC() 객체를 기본 매개변수로 생성
clf.set_params(kernel='linear').fit(X, y) # SVC() 객체의 'kernel' 매개변수를 'linear'로 설정 후 학습
SVC(kernel='linear')
clf.predict(X[:5])    # 0~4 번째 데이터를 예측
array([0, 0, 0, 0, 0])
clf.set_params(kernel='rbf').fit(X, y)  # 'kernel' 매개변수를 'rbf'로 설정
SVC()
clf.predict(X[:5])    # 0~4 번째 데이터를 예측
array([0, 0, 0, 0, 0])

여기에서 먼저 추정기가 생성된 후 ‘kernel’ 매개변수의 기본 값인 rbfSVC.set_params()를 통해 linear 로 변경되고 두 번째 예측을 수행하기 위해 다시 rbf로 변경됩니다.

Multiclass vs. multilabel fitting

다중 클래스 분류기를 사용할 때 수행되는 학습 및 예측 작업은 대상 데이터의 형식에 따라 다릅니다:

from sklearn.svm import SVC
from sklearn.multiclass import OneVsRestClassifier
from sklearn.preprocessing import LabelBinarizer

X = [[1, 2], [2, 4], [4, 5], [3, 2], [3, 1]]
y = [0, 0, 1, 1, 2]

classif = OneVsRestClassifier(estimator=SVC(random_state=0))  # SVC 추정기를 기본으로 하는 다중 분류기 생성
classif.fit(X, y).predict(X)    # 훈련 후 X값을 예측
array([0, 0, 1, 1, 2])

위의 경우, 분류기는 다중 클래스 레이블의 1d 배열에 적합하므로 predict() 메서드는 해당하는 1d 예측값을 제공합니다. 클래스 레이블을 이진화하여 나타낼 수도 있습니다.

ex) 0 -> [1, 0, 0], 1 -> [0, 1, 0], 2 -> [0, 0, 1]

y = LabelBinarizer().fit_transform(y)   # y 값을 이진화하여 변환
classif.fit(X, y).predict(X)            # 변환한 값을 학습 레이블로 하여 학습 후 예측
array([[1, 0, 0],
       [1, 0, 0],
       [0, 1, 0],
       [0, 0, 0],
       [0, 0, 0]])

여기서, 분류기는 LabelBinarizer를 사용한 y의 2d 이진화 표현으로 fit() 했습니다. 이번 predict() 의 경우는 다중 레이블 예측값인 2차원 배열을 반환합니다.

모두 0을 반환하는 네 번째와 다섯 번째 인스턴스는 세 레이블 중 어느 것도 fit 하지 않음을 나타냅니다. 다중 레이블 출력을 사용하면 인스턴스가 여러 레이블에 할당될 수도 있습니다.

from sklearn.preprocessing import MultiLabelBinarizer
y = [[0, 1], [0, 2], [1, 3], [0, 2, 3], [2, 4]]
y = MultiLabelBinarizer().fit_transform(y)
classif.fit(X, y).predict(X)
array([[1, 1, 0, 0, 0],
       [1, 0, 1, 0, 0],
       [0, 1, 0, 1, 0],
       [1, 0, 1, 0, 0],
       [1, 0, 1, 0, 0]])

이 분류기는 여러 레이블이 각각에 할당된 인스턴스에 적합합니다. MultiLabelBinarizer 는 2차원 배열의 각 원소 값이 1인 이진화 다중 레이블을 만드는 데 사용됩니다. 결과적으로, predict()는 각 인스턴스에 대해 여러 예측 레이블이 있는 2차원 배열을 반환합니다.


ⓒ 2007 - 2021, scikit-learn developers (BSD License). Show this page source


댓글남기기