Machine Learning/Basic

[3-1] k-최근접 이웃 회귀

jwjwvison 2021. 4. 5. 13:58

이 포스팅은 혼자 공부하는 머신러닝 + 딥러닝 책을 공부하고 정리한 것 입니다.


 지도 학습 알고리즘은 크게 분류와 회귀(regression)으로 나뉜다. 분류는 앞에서 다루었는데 말 그대로 샘플을 몇 개의 클래스 중 하나로 분류하는 문제이다. 회귀는 클래스 중 하나로 분류하는 것이 아니라 임의의 어떤 숫자를 예측하는 문제이다. 예를 들면 내년도 경제 성장률을 예측하거나 배달이 도착할 시간을 예측하는 것이 회귀 문제이다. 또 이번에 만들 프로그램인 농어의 무게를 예측하는 것도 회귀가 된다. 회귀는 정해진 클래스가 없고 임의의 수치를 출력한다.

 

 k-최근접 이웃 분류 알고리즘은 예측하려는 샘플에 가장 가까운 샘플 k개를 선택하고 이 샘플들의 클래스를 확인하여 다수 클래스를 새로운 샘플의 클래스로 예측한다.

 

k-최근접 이웃 회귀도 간단하다. 분류와 똑같이 예측하려는 샘플에 가장 가까운 샘플 k개를 선택한다. 하지만 회귀이기 때문에 이웃한 샘플의 타깃은 어떤 클래스가 아니라 임의의 수치이다. 이웃 샘플의 수치를 사용해 새로움 샘플 x의 타킷을 예측하는 방법은 이 수치들의 평균을 구하면 된다.

 

데이터 준비

농어의 길이만 있어도 무게를 잘 예측할 수 있다고 생각이 드니 농어의 길이가 특성이고 무게가 타깃이 될 것이다.

import numpy as np

perch_length = np.array([8.4, 13.7, 15.0, 16.2, 17.4, 18.0, 18.7, 19.0, 19.6, 20.0, 21.0,
       21.0, 21.0, 21.3, 22.0, 22.0, 22.0, 22.0, 22.0, 22.5, 22.5, 22.7,
       23.0, 23.5, 24.0, 24.0, 24.6, 25.0, 25.6, 26.5, 27.3, 27.5, 27.5,
       27.5, 28.0, 28.7, 30.0, 32.8, 34.5, 35.0, 36.5, 36.0, 37.0, 37.0,
       39.0, 39.0, 39.0, 40.0, 40.0, 40.0, 40.0, 42.0, 43.0, 43.0, 43.5,
       44.0])
perch_weight = np.array([5.9, 32.0, 40.0, 51.5, 70.0, 100.0, 78.0, 80.0, 85.0, 85.0, 110.0,
       115.0, 125.0, 130.0, 120.0, 120.0, 130.0, 135.0, 110.0, 130.0,
       150.0, 145.0, 150.0, 170.0, 225.0, 145.0, 188.0, 180.0, 197.0,
       218.0, 300.0, 260.0, 265.0, 250.0, 250.0, 300.0, 320.0, 514.0,
       556.0, 840.0, 685.0, 700.0, 700.0, 690.0, 900.0, 650.0, 820.0,
       850.0, 900.0, 1015.0, 820.0, 1100.0, 1000.0, 1100.0, 1000.0,
       1000.0])

 

import matplotlib.pyplot as plt

plt.scatter(perch_length,perch_weight)
plt.xlabel('length')
plt.ylabel('weigth')
plt.show()

 

사이킷런에 사용할 훈련 세트는 2차원 배열이어야 하기때문에 1차원 배열인 train_input, test_input을 2차원 배열로 reshape() 함수를 이용해서 바꿔줘야 한다.

train_input,test_input,train_target,test_target=train_test_split(perch_length,
                                                                perch_weight,random_state=42)
                                                                
train_input=train_input.reshape(-1,1)
test_input=test_input.reshape(-1,1)
print(train_input.shape,test_input.shape)

 

 

결정계수(R^2)

사이킷런에서 k-최근접 이웃 회귀 알고리즘을 구현한 클래스는 KNeighborsRegressor이다.

from sklearn.neighbors import KNeighborsRegressor

knr=KNeighborsRegressor()
knr.fit(train_input,train_target)
print(knr.score(test_input,test_target))

 

아주 좋은 점수인데 이 점수는 무엇일까?

분류의 경우는 테스트 세트에 있는 샘플을 정확하게 분류한 개수의 비율이다. 정확도라고 불렸다. 간단히 말해 정답을 맞힌 개수의 비율이다. 회귀에서는 정확한 숫자를 맞힌다는 것은 거의 불가능 하다. 예측 하는 값이나 타깃 모두 임의의 수치이기 때문이다.

회귀의 경우에는 조금 다른 값으로 평가하는데 이 점수를 결정계수(coefficient of determination)라고 부른다. 또는 간단히 R^2라고도 부른다.  다음과 같은 식으로 계산된다.

만약 타깃의 평균 정도를 예측하는 수준이라면 (즉 분자와 분모가 비슷해져) R^2은 0에 가까워 지고, 타깃이 예측에 아주 가까워지면 (분모가 0에 가까워지기 때문에) 1에 가까운 값이 된다.

 

타깃과 예측한 값 사이의 차이를 구해 보면 어느 정도 예측이 벗어났는지 가늠하기 좋다. 사이킷런은 sklearn.metrics 패키지 아래 여러가지 측정 도구를 제공한다. 이중에서 mean_absolute_error는 타깃과 예측의 절대값 오차를 평균하여 반환한다.

from sklearn.metrics import mean_absolute_error

test_prediction=knr.predict(test_input)  #테스트 세트에 대한 예측을 만든다
mae=mean_absolute_error(test_target,test_prediction)   #테스트 세트에 대한 평균 절댓값 오차를 계산한다
print(mae)

 

결과에서 예측이 평균적으로 19g 정도 타깃갑소가 다르다는 것을 알 수 있다.

지금까지는 훈련 세트를 사용해 모델을 훈련하고 테스트 세트로 모델을 평가했다. 그런데 훈련 세트를 사용해 평가해 보면 어떨까? 즉 score() 메서드에 훈련 세트를 전달하여 점수를 출력해 보는것이다. 이 값은 테스트 세트의 점수와 다를 것이다. 

 

과대적합 vs 과소적합

print(knr.score(train_input,train_target))

테스트 세트를 사용한 점수보다 작다

 만약 훈련 세트에서 점수가 굉장히 좋았는데 테스트 세트에서는 점수가 굉장히 나쁘다면 모델이 훈련 세트에 과대적합(overfitting) 되었다고 말한다. 즉 훈련 세트에만 잘 맞는 모델이라 테스트 세트와 나중에 실전에 투입하여 새로운 샘플에 대한 예측을 만들 때 잘 동작하지 않을 것이다. 

 반대로 훈련 세트보다 테스트 세트의 점수가 높거나 두 점수가 모두 너무 낮은 경우는 모델이 훈련 세트에 과소적합(underfitting) 되었다고 말한다. 즉 모델이 너무 단순하여 훈련 세트에 적절히 훈련되지 않은 경우이다. 이런 현상의 또 다른 원인은 훈련 세트와 테스트 세트의 크기가 매우 작기 때문이다. 데이터가 작으면 테스트 세트가 훈련 세트의 특징을 따르지 못할 수 있다.

 

 

이 문제를 해결하기 위해서는 모델을 조금 더 복잡하게 만들면 된다. k-최근접 이웃 알고리즘으로 모델을 더 복잡하게 만드는 방법은 이웃의 개수 k를 줄이는 것이다. 이웃의 개수를 줄이면 훈련 세트에 있는 국지적인 패턴에 민감해지고, 이웃의 개수를 늘리면 데이터 전반에 있는 일반적인 패턴을 따를 것이다.

 

knr.n_neighbors=3

knr.fit(train_input,train_target)
print(knr.score(train_input,train_target))

print(knr.score(test_input,test_target))

 

 

결론


 회귀는 임의의 수치를 예측하는 문제이다. 농어의 길이를 사용해 무게를 예측하는 k-최근접 이웃 회귀 모델을 만들었다. k-최근접 이웃 회귀 모델은 분류와 동일하게 가장 먼저 가까운 k개의 이웃을 찾고 이웃 샘플의 타깃값을 평균하여 이 샘플의 예측값으로 사용한다.

 사이킷런은 회귀 모델의 점수로 R^2, 즉 결정계수 값을 반환한다. 이 값은 1에 가까울수록 좋다. 정량적인 평가를 하고 싶다면 사이킷런에서 제공하는 다른 평가도구를 사용할 수 있다. 대표적으로 절댓값 오차가 있다.

 모델을 훈련하고 나서 훈련 세트와 테스트 세트에 대해 모두 평가 점수를 구할 수 있다. 훈련 세트의 점수와 테스트 세트의 점수 차이가 크면 좋지 않다. 일반적으로 훈련 세트의 점수가 테스트 세트보다 조금 더 높다. 만약 테스트 세트의 점수가 너무 낮다면 모델이 훈련 세트에 과도하게 맞춰진 것이다. 이를 과대적합 이라고 한다. 반대로 테스트 세트 점수가 너무 높거나 두 점수가 모두 낮으면 과소적합이다.

 과대적합일 경우 모델을 덜 복잡하게 만들어야 한다. k-최근접 이웃의 경우 k값을 늘린다. 과소 적합일 경우 모델을 더 복잡하게 만들어야 한다. k-최근접 이웃의 경우 k값을 줄이는 것이다.

'Machine Learning > Basic' 카테고리의 다른 글

[3-3] 특성 공학과 규제  (0) 2021.04.06
[3-2] 선형 회귀  (0) 2021.04.05
[2-2] 데이터 전처리  (0) 2021.04.04
[2-1] 훈련 세트와 테스트 세트  (0) 2021.04.03
[1] 머신러닝 맛보기 - 마켓과 머신러닝  (0) 2021.04.03