✨ 지도 학습은 입력과 출력 샘플 데이터가 있고, 주어진 입력으로부터 출력을 예측하고자 할 때 사용
지도 학습에는 분류(classification)와 회귀(regression)이 있다.
분류는 미리 정의된, 가능성 있는 여러 클래스 레이블 중 하나를 예측하는 것이다.
이진 분류( binary classification)
- 두 개의 클래스로 분류
- 질문의 답이 예/아니오만 나오는 경우
다중 분류( multiclass classification )
- 셋 이상의 클래스로 분류
회귀는 연속적인 숫자, 또는 실수를 예측하는 것이다.
예시
- 어떤 사람의 교육 수준, 나이, 주거지를 바탕으로 연간 소득을 예측하는 것이 예측
- 옥수수 농장에서 전년도 수확량과 날씨, 고용 인원수 등으로 올해 수확량을 예측
일반화( generalization )
과대 적합( overfitting )
과소 적합( underfitting )
- 모델을 복잡하게 할수록 훈련 데이터에 대해서는 더 정확히 예측할 수 있다.
- 하지만 너무 복잡해지면 훈련 세트의 각 데이터 포인트에 너무 민감해져 새로운 데이터에 잘 일반화 되지 못한다.
- ✨✨ 일반화 성능이 최대가 되는 최적점에 있는 모델을 찾아야 한다.
forge
데이터셋은 인위적으로 만든 이진 분류 데이터셋import matplotlib.pyplot as plt
%matplotlib inline
import mglearn
# 데이터셋을 만든다.
x, y = mglearn.datasets.make_forge()
# 산점도를 그린다.
mglearn.discrete_scatter(x[:, 0], x[:, 1], y)
plt.legend(['클래스 0', '클래스 1'], loc=4)
plt.xlabel('첫 번째 특성')
plt.ylabel('두 번째 특성')
print('x.shape:', x.shape)
wave
데이터셋을 사용x, y = mglearn.datasets.make_wave(n_samples=40)
plt.plot(x, y, 'o')
plt.ylim(-3, 3)
plt.xlabel('특성')
plt.ylabel('타깃')
📍 위스콘신 유방암 데이터셋 사용
자세한 정보는
cancer.DESCR
에서 확인 가능
from sklearn.datasets import load_breast_cancer
import numpy as np
cancer = load_breast_cancer()
print('cancer.key(): \n', cancer.keys())
print('유방암 데이터의 형태: ', cancer.data.shape)
print('클래스별 샘플 개수: \n', {n: v for n, v in zip(cancer.target_names, np.bincount(cancer.target))})
print('특성 이름: \n', cancer.feature_names)
~~~>
cancer.key():
dict_keys(['data', 'target', 'frame', 'target_names', 'DESCR', 'feature_names', 'filename'])
유방암 데이터의 형태: (569, 30)
클래스별 샘플 개수:
{'malignant': 212, 'benign': 357}
특성 이름:
['mean radius' 'mean texture' 'mean perimeter' 'mean area'
'mean smoothness' 'mean compactness' 'mean concavity'
'mean concave points' 'mean symmetry' 'mean fractal dimension'
'radius error' 'texture error' 'perimeter error' 'area error'
'smoothness error' 'compactness error' 'concavity error'
'concave points error' 'symmetry error' 'fractal dimension error'
'worst radius' 'worst texture' 'worst perimeter' 'worst area'
'worst smoothness' 'worst compactness' 'worst concavity'
'worst concave points' 'worst symmetry' 'worst fractal dimension']
📍 보스턴 주택가격 데이터셋 사용
from sklearn.datasets import load_boston
boston = load_boston()
print('데이터의 형태: ', boston.data.shape)
x, y = mglearn.datasets.load_extended_boston()
print('x.shape: ', x.shape)
~~>
데이터의 형태: (506, 13)
x.shape: (506, 104)
# 최근접 이웃을 한개 사용하는 경우
mglearn.plots.plot_knn_classification(n_neighbors=1)
~~>
# 최근접 이웃을 세개 사용하는 경우
mglearn.plots.plot_knn_classification(n_neighbors=3)
~~>
# 훈련 데이터와 테스트 데이터로 나눠 일반화 성능을 평가하기
from sklearn.model_selection import train_test_split
x, y = mglearn.datasets.make_forge()
x_train, x_test, y_train, y_test = train_test_split(x, y, random_state=0)
# 모델 학습시키기
from sklearn.neighbors import KNeighborsClassifier
clf = KNeighborsClassifier(n_neighbors=3)
clf.fit(x_train, y_train)
print('테스트 세트 예측: ', clf.predict(x_test))
print('테스트 세트 정확도: {:.2f}'.format(clf.score(x_test, y_test)))
~~>
테스트 세트 예측: [1 0 1 0 1 0 0]
테스트 세트 정확도: 0.86
fig, axes = plt.subplots(1, 3, figsize=(10, 3))
for n_neighbors, ax in zip([1, 3, 9], axes):
# fit 메소드는 self 오브젝트를 리턴
# 그래서 객체 생성과 fit 메소드를 한 줄에 쓸 수 있다.
clf = KNeighborsClassifier(n_neighbors=n_neighbors).fit(x, y)
mglearn.plots.plot_2d_separator(clf, x, fill=True, eps=0.5, ax=ax, alpha=.4)
mglearn.discrete_scatter(x[:, 0], x[:, 1], y, ax=ax)
ax.set_title('{} 이웃'.format(n_neighbors))
ax.set_xlabel('특성 0')
ax.set_ylabel('특성 1')
axes[0].legend(loc=3)
~~>
📍 유방암 데이터셋을 이용
# 유방암 데이터셋을 이용
from sklearn.datasets import load_breast_cancer
cancer = load_breast_cancer()
x_train, x_test, y_train, y_test = train_test_split(cancer.data, cancer.target, stratify=cancer.target, random_state=66)
training_accuracy = []
test_accuracy = []
# 1 에서 10 까지 n_neighbors를 적용
neighbors_settings = range(1, 11)
for n_neighbors in neighbors_settings:
# 모델 생성
clf = KNeighborsClassifier(n_neighbors=n_neighbors)
clf.fit(x_train, y_train)
# 훈련 세트 정확도 저장
training_accuracy.append(clf.score(x_train, y_train))
# 일반화 정확도 저장
test_accuracy.append(clf.score(x_test, y_test))
plt.plot(neighbors_settings, training_accuracy, label='훈련 정확도')
plt.plot(neighbors_settings, test_accuracy, label='테스트 정확도')
plt.ylabel('정확도')
plt.xlabel('n_neighbors')
plt.legend()
~~>
n_neighbors 수
( x 축 )에 따른 훈련 세트와 테스트 세트 정확도( y축 )를 보여준다.📍 wave 데이터셋 이용
# 최근접 이웃을 1개로 설정했을 때
mglearn.plots.plot_knn_regression(n_neighbors=1)
~~>
# 최근접 이웃을 3개로 설정했을 때
mglearn.plots.plot_knn_regression(n_neighbors=3)
~~>
📍 scikit-learn KNeighborsRegressor
라이브러리 사용
from sklearn.neighbors import KNeighborsRegressor
x, y = mglearn.datasets.make_wave(n_samples=40)
# wave 데이터셋을 훈련 세트와 테스트 세트로 나누기
x_train, x_test, y_train, y_test = train_test_split(x, y, random_state=0)
# 이웃의 수를 3으로 하여 모델의 객체를 만들기
reg = KNeighborsRegressor(n_neighbors=3)
# 훈련 데이터와 타깃을 사용하여 모델 학습
reg.fit(x_train, y_train)
print('테스트 세트 예측 :\n', reg.predict(x_test))
print('테스트 세트 R^2: {:.2f}'.format(reg.score(x_test, y_test)))
~~>
테스트 세트 예측 :
[-0.05396539 0.35686046 1.13671923 -1.89415682 -1.13881398 -1.63113382
0.35686046 0.91241374 -0.44680446 -1.13881398]
테스트 세트 R^2: 0.83
fig, axes = plt.subplots(1, 3, figsize=(15, 4))
# -3 과 3 사이에 1,000개의 데이터 포인트를 만든다.
line = np.linspace(-3, 3, 10000).reshape(-1, 1)
for n_neighbors, ax in zip([1, 3, 9], axes):
# 1, 3, 9 이웃을 사용한 예측
reg = KNeighborsRegressor(n_neighbors=n_neighbors)
reg.fit(x_train,y_train)
ax.plot(line, reg.predict(line))
ax.plot(x_train, y_train, '^', c=mglearn.cm2(0), markersize=8)
ax.plot(x_test, y_test, 'v', c=mglearn.cm2(1), markersize=8)
ax.set_title('{} 이웃의 훈련 스코어 : {:.2f} 테스트 스코어 : {:.2f}'
.format(n_neighbors, reg.score(x_train, y_train), reg.score(x_test, y_test)))
ax.set_xlabel('특성')
ax.set_ylabel('타깃')
axes[0].legend(['모델 예측', '훈련 데이터 / 타깃', '테스트 데이터 / 타깃'], loc='best')
~~>
일반적으로 KNeighbors 분류기
에 중요한 매개변수는 두 개이다.
KNN의 장점은 이해하기 매우 쉬운 모델이라는 점
많이 조정하지 않아도 자주 좋은 성능을 발휘한다.
최근접 이웃 모델은 매우 빠르게 만들 수 있지만, 훈련 세트가 매우 크면 예측이 느려진다.
KNN 알고리즘을 사용할 땐 데이터 전처리하는 과정이 중요
많은 특성을 가진 데이터 셋에는 잘 동작하지 않으며, 특성 값 대부분이 0
인 데이터셋과는 특히 잘 작동하지 않는다.
K-최근접 이웃 알고리즘이 이해하긴 쉽지만, 예측이 느리고 많은 특성을 처리하는 능력이 부족해 현업에서는 잘 쓰지 않는다.
이런 단점이 없는 알고리즘이 선형 모델이다.