앎을 경계하기

Machine Learning/scikit-learn diary

2. 사이킷런을 사용하는 머신러닝

양갱맨 2021. 9. 28. 12:14

머신러닝이란?

다수의 데이터가 모여있는 집합인 데이터셋으로부터 데이터 과학자가 고려하고 있는 문제를 학습하고, 모델이 전혀 보지 못했던 데이터셋을 통해 예측하는 것.

그리고 이 예측의 정확도가 높을 수록 성능이 좋은 모델이라고 할 수 있다.

머신러닝에서 다루는 문제의 카테고리를 다음과 같이 나눌 수 있다.

  1. supervised learning
    a. classification : 2개 또는 이상의 클래스에 속하는 샘플들을 학습하고 클래스 라벨링이 되어있지 않은 데이터를 입력으로 줬을 때 클래스를 맞추는(분류하는) 문제, 분류 문제는 이산적인 카테고리로 구성되어 있다.
    b. regression : 하나 또는 이상의 연속적인 변수들로 구성된 출력을 예측하는 문제
  2. unsupervised learning
    clustering(유사한 데이터끼리 그룹화하는 문제), density estimation(입력 공간 안에서 데이터의 분포를 결정하는 밀도 추정 문제)등의 문제를 풀기 위함

Scikit-learn datasets

scikit-learn에서는 매우 유명한 데이터셋(붓꽃데이터(iris dataset), 숫자 데이터(digits dataset), 당뇨병데이터(diabetes dataset) 등)을 제공하고 있다.

데이터셋을 불러오는 연습을 해보자.

from sklearn import datasets
iris = datasets.load_iris()
digits = datasets.load_digits()
>>> digits.data
array([[ 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
array([0, 1, 2, ..., 8, 9, 8])
>>> digits.data.shape
(1797, 64)
>>> digits.target.shape
(1797,)

data를 통해 데이터 값을 확인할 수 있고, target을 통해 각 데이터에 대한 라벨 값을 확인할 수 있다.
사이킷런에서 제공하는 datan_samples(샘플 개수), n_featuers(특징 수) 형태로 저장된다.
digits 데이터셋의 경우, 이미지이기 때문에 원본 이미지 데이터로 보고 싶다면 digits.images[0]로 볼 수 있다.

>>> 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.]])
>>> digits.images[0].shape
(8, 8)

scikit-learn estimator 사용하기

위에서 로드한 digits데이터셋을 기반으로 svm 모델을 적용해보자.
scikit-learn은 파이썬에서 sklearn으로 사용한다.
그리고 각 모델을 학습하는 것은 fit(X, y), 예측은 predict(T) 메소드를 사용하면 된다.

>>> from sklearn import svm
>>> classifier = svm.SVC(gamma=0.001, C=100)

svm.SVC는 support vector classification 모델을 말한다.
모델을 정의했으니 학습과 예측을 진행해보자.

>>> classifier.fit(digits.data[:-1], digits.target[:-1]) # 학습 데이터와 그에 맞는 라벨 데이터
SVC(C=100, gamma=0.001)
>>> classifier.predict(digits.data[-1:]) # 맨 마지막 데이터를 테스트 데이터로 사용
array([8]) # 예측 값

위에서 사용된 digits.data[:-1], digits.data[-1:] 같은 인덱싱은 주의해야 한다. 익숙하지 않다면 직접 출력해보면서 확인하는 것도 좋다.
모델 학습에 사용된 데이터는 전체 1797개 데이터 중 마지막 데이터를 뺀 1796개이고, 예측에 사용된 테스트 데이터는 학습에서 제외된 마지막 데이터 1개이다.
모델의 테스트 데이터 예측값은 8이다.

>>> digits.target[-1]
8

실제 정답과 비교해보니 같은 8로 맞춘 것을 알 수 있다.

Type

특별한 경우가 아니면 보통 인풋 타입은 float64을 갖는다.

>>> import numpy as np
>>> from sklearn import random_projection
>>> rng = np.random.RandomState(0)
>>> X = rng.rand(10, 2000)
>>> X = np.array(X, dtype='float32')
>>> X.dtype
dtype('float32')
>>> transformer = random_projection.GaussianRandomProjection()
>>> X_new = transformer.fit_transform(X)
>>> X_new.dtype
dtype('float64')

그리고 정수형의 타겟이 설정되면 아웃풋도 정수형, 문자형의 타겟이 들어가면 문자형의 아웃풋을 출력한다.

>>> from sklearn import datasets
>>> from sklearn.svm import SVC
>>> iris = datasets.load_iris()
>>> clf = SVC()
>>> clf.fit(iris.data, iris.target)
SVC()
>>> list(clf.predict(iris.data[:3]))
[0, 0, 0]
>>> clf.fit(iris.data, iris.target_names[iris.target])
SVC()
>>> list(clf.predict(iris.data[:3]))
['setosa', 'setosa', 'setosa']

하이퍼파라미터 설정

모델을 학습시킬때 성능을 높이기 위해 하는 작업 중 하나가 하이퍼 파라미터(사람이 지정할 수 있는 파라미터)를 설정하는 것이다.
set_params를 사용해서 파라미터를 설정한 후, 다시 fit을 통해 학습을 진행한다.

>>> import numpy as np
>>> from sklearn.datasets import load_iris
>>> from sklearn.svm import SVC
>>> X, y = load_iris(return_X_y=True)
>>> clf = SVC()
>>> clf.set_params(kernel='linear').fit(X,y)
SVC(kernel='linear')
>>> clf.predict(X[:5])
array([0, 0, 0, 0, 0])
>>> clf.set_params(kernel='rbf').fit(X,y)
SVC()
>>> clf.predict(X[:5])
array([0, 0, 0, 0, 0])

Multiclass vs Multilabel fitting

multiclass 분류기를 사용하면, 타겟을 0과 1이 아닌 멀티 클래스로 분류하는 것이 가능하다.

>>> 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))
>>> classif.fit(X, y).predict(X)
array([0, 0, 1, 1, 2])

target이 저장된 y를 LabelBinarizer()로 변형시켜주면 one-hot encoding 형식의 target을 얻을 수 있다.

>>> y = LabelBinarizer().fit_transform(y)
>>> classif.fit(X, y).predict(X)
array([[1, 0, 0],
       [1, 0, 0],
       [0, 1, 0],
       [0, 0, 0],
       [0, 0, 0]])

MultiLabelBinarizer()를 사용하면 한 데이터셋에 대해 여러 레이블을 할당할 수 있는 multilabel 출력을 얻을 수 있다.

>>> 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]])