앎을 경계하기

Machine Learning/scikit-learn diary

4. 사이킷런으로 지도 학습해보기 1

양갱맨 2021. 10. 5. 01:28

지도학습(Supervised learning)

모델이 학습할 데이터(X)와 그에 맞는 정답 레이블(y)쌍을 데이터셋으로 구성하여 사용하는 학습 방법

사이킷런에 있는 모든 지도학습용 estimator들은 fit(X, y) 형태로 학습하고 predict(X) 형태로 예측한다.
classification 문제라면 y는 특정 클래스가 될 것이고,
regression 문제라면 y는 연속적인 변수의 특정 값이다.


최근접 이웃 알고리즘과 차원의 저주 문제

KNN classifier를 사용하여 문제를 풀어보자.

import numpy as np
from sklearn import datasets
iris_X, iris_y = datasets.load_iris(return_X_y=True)
np.unique(iris_y)  #array([0,1,2])

KNN : k-Nearnest neighbors, k개의 인접한 이웃 데이터들을 같은 클래스로 보고 새로운 데이터가 주어졌을때, 그룹들 중 가장 유사한 형태의 그룹으로 분류함.

np.random.seed(0)#random seed 고정
indices = np.random.permutation(len(iris_X))
iris_X_train = iris_X[indices[:-10]]
iris_y_train = iris_y[indices[:-10]]
iris_X_test = iris_X[indices[-10:]]
iris_y_test = iris_y[indices[-10:]]

from sklearn.neighbors import KNeighborsClassifier
knn = KNeighborsClassifier()
knn.fit(iris_X_train, iris_y_train)

knn.predict(iris_X_test)  #array([1, 2, 1, 0, 0, 0, 2, 1, 2, 0])

iris_y_test  #array([1, 1, 1, 0, 0, 0, 2, 1, 2, 0])

KNN을 통해서 차원의 저주 문제를 이해할 수 있다.

차원의 저주란?

말그대로 데이터셋의 특징 차원이 늘어나면서 데이터셋에 비해 특징 차원이 커져 알고리즘 성능이 저하되는 것이다.
고차원일수록 데이터 간 거리가 멀어지게 되는데, 최근접 거리를 사용하여 데이터 간 클래스 분류를 하는 KNN 모델에게 고차원 데이터는 성능저하를 유발한다.


Linear regression

이번에는 선형 회귀 모델을 사용해보자.
적용할 데이터셋은 당뇨병 데이터셋으로 442명 환자들의 10개의 생리적 변수들(나이, 성별, 체중, 혈압 등)을 측정한 데이터셋이다.

diabetes_X, diabetes_y = datasets.load_diabetes(return_X_y=True)
diabetes_X_train = diabetes_X[:-20]
diabetes_X_test = diabetes_X[-20:]
diabetes_y_train = diabetes_y[:-20]
diabetes_y_test = diabetes_y[-20:]

from sklearn import linear_model
regr = linear_model.LinearRegression()
regr.fit(diabetes_X_train,diabetes_y_train)

print(regr.coef_)
'''
[ 3.03499549e-01 -2.37639315e+02  5.10530605e+02  3.27736980e+02
 -8.14131709e+02  4.92814588e+02  1.02848452e+02  1.84606489e+02
  7.43519617e+02  7.60951722e+01]
'''

np.mean((regr.predict(diabetes_X_test) - diabetes_y_test) ** 2) # MSE
'''
2004.5676026898218
'''

regr.score(diabetes_X_test, diabetes_y_test)
'''
0.5850753022690...
'''

Shrinkage

import numpy as np
from sklearn.linear_model import LinearRegression

X = np.c_[.5, 1].T
y = [.5, 1]
test = np.c_[0, 2].T
regr = LinearRegression()

import matplotlib.pyplot as plt
plt.figure()

np.random.seed(0)
for _ in range(6):
    this_X = .1 * np.random.normal(size=(2,1)) + X
    regr.fit(this_X, y)
    plt.plot(test, regr.predict(test))
    plt.scatter(this_X,y,s=3)

from sklearn.linear_model import Ridge

regr = Ridge(alpha=0.1)

plt.figure()
np.random.seed(0)
for _ in range(6):
    this_X = .1 * np.random.normal(size=(2,1)) + X
    regr.fit(this_X, y)
    plt.plot(test, regr.predict(test))
    plt.scatter(this_X,y,s=3)

이 예제는 bias(편향)/variance(분산) tradeoff에 대한 예제다.

ridge의 alpha값이 커질수록 편향이 커지고 분산이 낮아진다.

alphas = np.logspace(-4, -1, 6)
print([regr.set_params(alpha=alpha)
            .fit(diabetes_X_train, diabetes_y_train)
            .score(diabetes_X_test, diabetes_y_test)
        for alpha in alphas])
[0.5851110683883..., 0.5852073015444..., 0.5854677540698...,
 0.5855512036503..., 0.5830717085554..., 0.57058999437...]

Rigde regression에서의 편향을 regularization이다.

희소성(Sparsity)

regr = linear_model.Lasso()
scores = [regr.set_params(alpha=alpha)
               .fit(diabetes_X_train, diabetes_y_train)
               .score(diabetes_X_test, diabetes_y_test)
           for alpha in alphas]
best_alpha = alphas[scores.index(max(scores))]
regr.alpha = best_alpha
regr.fit(diabetes_X_train, diabetes_y_train)
Lasso(alpha=0.025118864315095794)
print(regr.coef_)
[   0.         -212.437...  517.194...  313.779... -160.830...
   -0.         -187.195...   69.382...  508.660...   71.842...]

우리가 앞에서 당뇨병 데이터셋을 봤을 때, 11개 차원의 features가 있었다. 이 중 하나는 타겟 변수이다.

공간은 매우 넓으나 타겟 변수같은 경우 값이 제한되어있어서 매우 비어있는 공간이라는 점이 유용하게 사용될 수 있다.

문제를 좀 더 쉽게 풀 수 있도록 도움이 되는 피쳐만 선택하는 것이 좋을 것이다.

Ridge regression은 기여도를 감소시키긴하지만 아예 0으로 설정할 수 없다.

Lasso는 일부 계수를 0으로 설정할 수 있다. 이러한 방법을 sparse method라고 한다.

regr = linear_model.Lasso()
scores = [regr.set_params(alpha=alpha)
               .fit(diabetes_X_train, diabetes_y_train)
               .score(diabetes_X_test, diabetes_y_test)
           for alpha in alphas]
best_alpha = alphas[scores.index(max(scores))]
regr.alpha = best_alpha
regr.fit(diabetes_X_train, diabetes_y_train)
Lasso(alpha=0.025118864315095794)
print(regr.coef_)
[   0.         -212.437...  517.194...  313.779... -160.830...
   -0.         -187.195...   69.382...  508.660...   71.842...]

scikit-learn에서는 같은 수학적인 문제를 풀기 위해 다른 알고리즘들을 사용할 수 있다.

예를 들어, Lasso의 경우, coordinate descent를 사용해서 lasso regression 문제를 풀고 큰 데이터셋에서 효율적이다.

또 다른 알고리즘은 LARS를 사용하는 LassoLars이다. 가중치 벡터가 매우 희소한 경우에 효율적이다.