#8. 최근접 이웃 알고리즘 실습, 이웃의 개수가 지도학습에 미치는 영향
2021. 12. 27. 11:14
* 본 내용의 예제는 '파이썬 라이브러리를 활용한 머신러닝'(안드레아스 뮐러, 세라 가이도 지음, 한빛미디어 출판)2장 지도학습의 실습 내용을 참고하여 작성되었습니다.
* 내용에 오류가 있을 수 있습니다.
k-Nearest Algorithm 분류 실습¶
In [4]:
import numpy as np
import matplotlib.pyplot as plt
import mglearn
X, y = mglearn.datasets.make_forge()
mglearn.discrete_scatter(X[:, 0], X[:, 1], y) #[:, 1] 은 [row_index, column_index]을 의미.
#https://dojang.io/mod/page/view.php?id=2208의 내용을 참조하자. (리스트 슬라이스)
plt.legend(["class 0", "class 1"], loc = 4) ##legend는 범례 추가하는 메서드
##https://matplotlib.org/stable/tutorials/intermediate/legend_guide.html 참조
plt.xlabel("The first trait")
plt.ylabel("The second trait")
print("X.shape: {}".format(X.shape))
X.shape: (26, 2)
/opt/anaconda3/lib/python3.9/site-packages/sklearn/utils/deprecation.py:87: FutureWarning: Function make_blobs is deprecated; Please import make_blobs directly from scikit-learn
warnings.warn(msg, category=FutureWarning)
In [5]:
mglearn.plots.plot_knn_classification(n_neighbors = 1) #이웃의 수를 1개로 설정
/opt/anaconda3/lib/python3.9/site-packages/sklearn/utils/deprecation.py:87: FutureWarning: Function make_blobs is deprecated; Please import make_blobs directly from scikit-learn
warnings.warn(msg, category=FutureWarning)
In [6]:
mglearn.plots.plot_knn_classification(n_neighbors = 3) #이웃의 수를 3개로 설정. 홀수개로 지정해야지 예비 데이터의 클래스를 예측할 수 있다.
/opt/anaconda3/lib/python3.9/site-packages/sklearn/utils/deprecation.py:87: FutureWarning: Function make_blobs is deprecated; Please import make_blobs directly from scikit-learn
warnings.warn(msg, category=FutureWarning)
scikit-learn으로 KNN알고리즘 적용¶
In [7]:
#훈련 데이터와 시험 데이터로 분할하기
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)
#KNeighborsClassifier 임포트 후 객체clf 만들기. 매개변수로 이웃의 수를 3으로 지정
from sklearn.neighbors import KNeighborsClassifier
clf = KNeighborsClassifier(n_neighbors = 3)
#훈련 세트로 분류 모델 학습. 지도 학습 분류 알고리즘에서 학습은 그저 훈련 데이터세트를 외우는 것이다.
clf.fit(X_train, y_train)
#시험 세트에 대해 모델을 사용해서 타겟값 예측. predict메서드를 사용한다.
print("테스트 데이터 예측: {}".format(clf.predict(X_test)))
#모델의 일반화 성능을 테스트하기 위해 score메서드를 사용한다.
print("테스트 세트 정확도: {: .2f}".format(clf.score(X_test, y_test)))
##{: .2f}는 처음(맨 왼쪽숫자, 즉 정수)부터 반올림해서 소수 둘째자리까지만 표시한다는 의미
테스트 데이터 예측: [1 0 1 0 1 0 0]
테스트 세트 정확도: 0.86
/opt/anaconda3/lib/python3.9/site-packages/sklearn/utils/deprecation.py:87: FutureWarning: Function make_blobs is deprecated; Please import make_blobs directly from scikit-learn
warnings.warn(msg, category=FutureWarning)
분류의 기준이 되는 결정 경계 Decision Boundary 시각화하기¶
In [9]:
fig, axes = plt.subplots(1, 3, figsize = (10, 3))
for n_neighbors, ax in zip([1, 3, 9], axes): #zip()동일 개수의 순차 자료형을 연관되게 묶어 하나의 튜플로 만든다.
#여기서는 각각의 이웃의 개수와 좌표평면을 각각 한 세트씩 묶는 것을 의미
clf = KNeighborsClassifier(n_neighbors = n_neighbors).fit(X, y) #clf객체 생성. 매개변수는 n_neighbors
#fit메서드가 self객체를 반환하므로 한번에 작성 가능
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("{} neighbors". format(n_neighbors))
ax.set_xlabel("trait_1")
ax.set_ylabel("trait_2")
axes[0].legend(loc = 3)
Out[9]:
<matplotlib.legend.Legend at 0x7f8fc0c89340>
이웃의 개수를 늘릴수록 결졍 경계가 부드러워진다. 부드러운 결정 경계는 모델이 보다 단순해졌음을 의미한다.
이웃을 적게 사용하면 모델의 복잡도가 올라가고, 많이 사용하면 낮아진다.
유방암 데이터세트를 통해 분류 모델의 복잡도 일반화 비교¶
In [13]:
#데이터 불러오기
from sklearn.datasets import load_breast_cancer
cancer = load_breast_cancer() #객체cancer 생성
print("cancer.keys(): \n{}". format(cancer.keys()))
print("유방암 데이터의 형태: {}".format(cancer.data.shape))
print("클래스별 샘플 개수: {}".format(
{n: v for n, v in zip(cancer.target_names, np.bincount(cancer.target))})) #zip함수로 cancer.target_names와 개수를 매칭
cancer.keys():
dict_keys(['data', 'target', 'frame', 'target_names', 'DESCR', 'feature_names', 'filename', 'data_module'])
유방암 데이터의 형태: (569, 30)
클래스별 샘플 개수: {'malignant': 212, 'benign': 357}
In [26]:
#유방암 데이터로 분류하기
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 = []
neighbors_settings = range(1, 11 ) #이웃의 수를 1부터 10명까지 살펴볼 것임
for n_neighbors in neighbors_settings: #이전 문장에서 볼 수 있듯이 neighbors_settings는 범위를 표현하는 객체.
#for문에 의해서 순차적으로 반복해서 n_neighbors에 숫자가 지정되고,
#그것이 KNeighborsClassifier에서 매개변수 역할을 한다. 1부터 10까지 반복.
clf = KNeighborsClassifier(n_neighbors = n_neighbors) #분류 알고리즘을 객체clf으로 표현
clf.fit(X_train, y_train) #객체clf의 메서드fit으로 훈련 데이터로 모델 학습하기
training_accuracy.append(clf.score(X_train, y_train)) #score메서드로 훈련 데이터의 정확도를 계산해 생성해둔 변수에 저장
test_accuracy.append(clf.score(X_test, y_test)) #위와 같이 시험 데이터의 정확도를 계산해 변수에 저장
#그래프 표현하기
plt.plot(neighbors_settings, training_accuracy, label = "Training Accuracy")
plt.plot(neighbors_settings, test_accuracy, label = "Test Accuracy")
plt.xlabel("n_neighbors")
plt.ylabel("Accuracy")
plt.legend()
Out[26]:
<matplotlib.legend.Legend at 0x7f8fc0f052b0>
K-최근접 이웃 알고리즘 회귀 분석¶
In [35]:
#wave데이터셋 불러오기
X, y = mglearn.datasets.make_wave(n_samples = 40)
plt.plot(X, y, 'g^') #plt.plot()의 세 번째 인자에는 포맷 문자열을 지정한다. ro는 빨간원, g^는 녹색세모, bs는 파란네모 등의 형식이다.
plt.ylim(-3, 3) #y축의 범위를 지정해준 것. x축은 입력되지 않았으니 자동으로 조건에 맞게 조정된다.
plt.xlabel("chararter")
plt.ylabel("target")
Out[35]:
Text(0, 0.5, 'target')
In [34]:
#1-최근접 이웃 회귀 모델에서의 예측
mglearn.plots.plot_knn_regression(n_neighbors = 1)
#초록색 별들은 시험 데이터. 시험 데이터의 특성값에 가장 가까운 훈련 데이터의 타깃값을 시험 데이터의 예측값으로 본다.
In [36]:
#3-최근접 이웃 회귀 모델에서의 예측
mglearn.plots.plot_knn_regression(n_neighbors = 3)
scikit-learn으로 KNN회귀 알고리즘 활용하기¶
In [43]:
#wave데이터를 불러와서 회귀 모델에 적용하기
from sklearn.neighbors import KNeighborsRegressor
X, y = mglearn.datasets.make_wave(n_samples = 40)
#유방암 데이터셋은 호출해서 사용했다. 그리고 호출한 데이터셋(load_breast_cancer())을 객체cancer에 저장했다.
#여기서는 그와 조금 다르게 wave데이터셋을 40개 크기로 생성해서 X, y 객체에 지정했다.
#이렇게 하면 유방암 데이터와 달리 train_test_split()함수에서 X와 y를 따로 정의할 필요가 없다.
X_train, X_test, y_train, y_test = train_test_split(X, y, random_state = 0) #난수 생성기 매개변수는 0으로 고정. 항상 같은 결과 나오게
reg = KNeighborsRegressor(n_neighbors = 3) #reg객체를 생성해 회귀 모델 표현(모델이 객체 생성). 이웃의 개수는 3으로 지정
reg.fit(X_train, y_train)
#테스트 세트에 대한 예측 결과
print("predict test set: \n{}".format(reg.predict(X_test)))
#테스트 세트 정확도 평가
print("score test set accuracy: {:.2f}".format(reg.score(X_test, y_test))) #{:.2f}는 소숫점 둘째 자리까지만 반올림해서 표현한다는 뜻
predict test set:
[-0.05396539 0.35686046 1.13671923 -1.89415682 -1.13881398 -1.63113382
0.35686046 0.91241374 -0.44680446 -1.13881398]
score test set accuracy: 0.83
KNeighborsRegressor 으로 분석하기¶
In [59]:
fig, axes = plt.subplots(1, 3, figsize = (15, 4)) #plt.subplot(열, 칼럼, 인덱스) 현재 코드에서는 1줄에 3개의 복수 그래프 생성
line = np.linspace(-3, 3, 1000).reshape(-1, 1) #-3과 3tkdldp 1000개의 데이터포인트 만들기
for n_neighbors, ax in zip([1, 3, 9], axes): #이웃의 개수와 좌표평면을 하나씩 매칭
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(
"Training score of {} neighbor(s): {:.2f} \n test score: {:.2f}". format(
n_neighbors, reg.score(X_train, y_train),reg.score(X_test, y_test)))
ax.set_xlabel("trait")
ax.set_ylabel("target")
axes[0].legend(["Model prediction", "Train data/target",
"Test data/target"], loc = 'best')
Out[59]:
<matplotlib.legend.Legend at 0x7f8f8cd2a940>
이웃의 개수를 많이 설정할수록 데이터 포인트에 훈련 데이터가 미치는 영향이 줄어든다.
따라서 이웃의 개수가 많을수록 훈련 데이터에 영향을 덜 받으면서 보다 안정된 예측을 할 수 있다.
'배우는 것 > Maching Learning' 카테고리의 다른 글
#10. 선형 모델, 선형 회귀, 릿지 회귀, 라쏘 회귀, 복잡도 제어 (0) | 2021.12.27 |
---|---|
#9. 과적합, 과소적합, 일반화, 이전 글에 대한 배경지식 확장 (0) | 2021.12.27 |
#7. 파이썬 기본지식 공부(2)_스칼라형, 튜플, 리스트, 사전 (0) | 2021.12.23 |
#6. 파이썬 기본지식 공부(1) (0) | 2021.12.21 |
#5. 지도학습에서의 과적합화 (0) | 2021.12.20 |