Recent Posts
Recent Comments
Link
Today
Total
03-11 06:38
관리 메뉴

Hippo's data

ch2지도학습_K-최근접이웃 K-Neareset Neighbors(K-NN) 본문

ML(Machine Learning)/책: 파이썬 라이브러리를 활용한 머신러닝(2판)

ch2지도학습_K-최근접이웃 K-Neareset Neighbors(K-NN)

Hippo's data 2023. 9. 7. 22:45
728x90

이제부터 지도학습 알고리즘에 대해 알아보겠습니다

 

# 지도학습이란? 

-> 입력데이터를 통해 출력을 맞추는 것 

맞추는 방식은 크게 2가지로 나뉘는데요 

1. 분류 classifiaction 2. 회귀 regression

 

# 분류classifiaction

-> 여러 클래스 중 하나를 맞추는 것(예측하기) 

(이진binary 분류 - 두개 클래스로 분류 / 다중multicalss 분류 - 셋 이상의 클래스로 분류)

예) 스팸이메일 분류(Yes or No)  /  ch1의 붓꽃의 꽃잎, 꽃받침의 폭과 길이로 품종 예측 

 

 

# 회귀 regression

-> 연속적인 숫자(실수)를 맞추는 것

예) 교육수준, 나이, 거주지 등을 이용해 소득을 예측

 

# 일반화, 과대적합, 과소적합

훈련데이터를 통해 학습한 모델이 새로운 데이터도 잘 처리 하는지 평가할 때 자주 사용되는 용어

일반화 generalization

-> 훈련데이터를 적절히 학습해서 테스트데이터(새로운 데이터)도 정확하게 예측

-> 훈련데이터 뿐만 아니라 테스트 데이터에서도 잘 예측한다 = 훈련데이터에서 테스트데이터로 일반화되었다 

과대적합 overfitting

-> 훈련데이터를 과하게 학습해서 새로운데이터에 일반화 하기 어려운 상태(너무 복잡한 모델)

과소적합 underfitting

-> 훈련데이터도 제대로 학습하지 못함(너무 간단한 모델)

# 과대적합을 피하는 법

-> 적절한 학습을 통해 적절한 모델 복잡도로 모델생성 or 다양한 데이터로 학습진행 

-> 단지 데이터 양이 많다고 해서 좋은 모델을 만들 수 있는 건 아님(중복되거나 비슷한 데이터는 별로 의미 없음)

-> '다양한' 데이터가 필요함 

 

그렇다면 K-최근접 이웃의 분류와 회귀를 실습해보도록 하자

 

# K-최근접 이웃 분류classification 실습

-> 가장 가까운 k개의 값으로 예측 (동점상황 일어나지 않게 보통 k는 홀수로 설정 3, 5, 7 ...)

mglearn.plots.plot_knn_classification(n_neighbors=5)
# 최근접 이웃 분류

-> 가까운 5개의 값으로 예측

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 객체 생성 ( n_neighbors=3 이웃의 수 설정)

clf.fit(X_train, y_train)

-> fit을 이용해 학습진행 ( KNeighborsClassifier의 학습은 예측시 이웃을 찾을 수 있도록 데이터를 저장하는것)

print("테스트 세트 예측:", clf.predict(X_test))

-> 테스트 세트 예측: [1 0 1 0 1 0 0]

-> predict 이용하여 예측 진행

print("테스트 세트 정확도: {:.2f}".format(clf.score(X_test, y_test)))

-> 테스트 세트 정확도: 0.86 

->모델 얼마나 잘 일반화 되었는지 score메서드에서 X_test와 y_test 비교 

fig, axes = plt.subplots(1, 3, figsize=(10, 3))

for n_neighbors, ax in zip([1, 9, 26], 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)
plt.show()

-> 예측값을 평면에 그려봄 -> 속한 클래스에 따라 평면 색칠
-> 이웃 1,3,9일때의 결정경계 표시
-> 이웃증가 -> 결정경계 부드러워짐 = 단순한 모델
-> 극단적 - X 데이터 이웃을 26개(전테 데이터)로 지정시 -> 26개 중 더 많이 해당하는 클래스(자료상은 0클래스)로 다 동일하게  예측함

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()
plt.show()

# 모델복잡도와 일반화 사이의 관계
-> 복잡도 증가할 수록(이웃 많아질수록) 훈련정확도는 상승 / 테스트 정확도는 상승후 하락

( k-nn에서는 이웃이 많아질수록 모델 복잡도가 증가)

# K-최근접 이웃 회귀regression 실습

mglearn.plots.plot_knn_regression(n_neighbors=3)

-> 이웃1개 -> 예측값 : 가장가까운 이웃 타겟값
-> 이웃 2개 이상 -> 예측값 : 가까운 이웃들의 평균 타겟값 

from sklearn.neighbors import KNeighborsRegressor
# 최근접 이웃 회귀모델 -> 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)

-> reg 객체 생성 후 fit으로 모델 학습

print("테스트 세트 예측:\n", reg.predict(X_test))

-> 테스트 세트 예측:
 [-0.05396539  0.35686046  1.13671923 -1.89415682 -1.13881398 -1.63113382
  0.35686046  0.91241374 -0.44680446 -1.13881398]

print("테스트 세트 R^2: {:.2f}".format(reg.score(X_test, y_test)))

-> 테스트 세트 R^2: 0.83

 

# scrore로 반환되는 결정계수 값이란?

-> 회귀모델 score -> 결정계수값 반환함
-> 결정계수 R^2 => y변동량 대비 모델 예측값 변동량 -> 모델이 자료를 얼마나 설명하는가(0.83 -> 83퍼센트 설명력가짐)
-> 1 -> 예측 완벽 / 0 -> y_train의 평균으로만 예측(y_hat = y_bar가 같아지므로)
-> 음수값 나올 수 있음(계산식과는 다르게 ) -> 예측과 타깃이 상반된 경우/일괄적으로 평균으로 예측한것보다 성능 떨어짐 -> 음수나올시 모델 폐기

fig, axes = plt.subplots(1, 3, figsize=(15, 4))
# -3 과 3 사이에 1,000 개의 데이터 포인트를 만듭니다
line = np.linspace(-3, 3, 1000).reshape(-1, 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")
plt.show()

-> 이웃1개 -> 훈련데이터 포인트 모두 지나감
-> 이웃 많아질수록 훈련데이터 잘 안맞더라도 더 안정되게 예측함 -> 일반화 관점 good 

 

# K-nn 중요 매개변수 -> 데이터간 거리, 이웃의 수
->  데이터간 거리 -> 대부분 유클리디안 거리사용 / metric 매개변수 사용(기본값 - 민코프스키거리)
->  이웃수 -> 거의 3, 5개로 적을때 잘 작동 / n_neighbors 매개변수 사용

->  장점 -> 이해하기 쉬움 / 적은 조정으로 좋은 성능냄
->  단점 -> 예측 느림(훈련세트 크면) / 많은 특성 처리 어려움 / 희소한 데이터 셋(타겟값이 쏠린)에 잘 작동하지 않음 -> 현업에서 거의 쓰이지 않음

 

다음 이시간에는 선형모델linear model로 돌아오겠습니다

728x90