STUDY

[AI] k-최근접 이웃 회귀

Dalseung 2022. 11. 6. 14:24

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]
     )

perch_length와 perch_weight이라는 numpy 배열을 만든다.

import matplotlib.pyplot as plt
plt.scatter(perch_length, perch_weight)
plt.xlabel('length')
plt.ylabel('weight')
plt.show()

image

scatter함수를 사용하여 산점도를 그리고, 그래프 x축에 length, y축에 weight를 입력하고 보여준다.

from sklearn.model_selection import train_test_split
train_input, test_input, train_target, test_target = train_test_split(
    perch_length, perch_weight, random_state=42)

train_test_split() 함수를 사용하여 훈련 세트와 테스트 세트로 나눈다.
이때, 책과 결과를 동일하게 유지하기 위해 random_state=42로 지정한다.
train_input과 test_input은 perch_length에서 나누는 것이고, train_target, test_target은 perch_weight에서 나눈다.

numpy의 reshape

test_array = np.array([1,2,3,4])
print(test_array.shape)

(4,)

사이킷런에 사용할 훈련세트는 2차원 배열이어야 하므로 test_array 이름의 numpy 배열을 만들어서 현재 test_array의 구조를 본다.

train_input = train_input.reshape(-1,1)
test_input = test_input.reshape(-1,1) # -1은 배열의 전체 원소의 개수
print(train_input.shape, test_input.shape)

(42, 1) (14, 1)

from sklearn.neighbors import KNeighborsRegressor
knr = KNeighborsRegressor()
knr.fit(train_input, train_target) # k-최근접 이웃 회귀 모델을 훈련
print(knr.score(test_input, test_target))

0.992809406101064

이 점수는 분류의 경우 테스트 세트에 있는 샘플을 정확하게 분류한 개수의 비율이다.
하지만 회귀에서는 정확한 숫자를 맞추기 매우 어렵기 때문에 결정계수라는 점수로 평가한다.

결정계수 R^2

$$
R^2 = 1 - (타깃 - 예측)^2의 합 / (타깃-평균)^2의 합
$$

위의 수식의 결과가 1에 가까워지면 예측과 타깃이 같아지는 것이다.

또한 0에 가까워지면 평균과 예측이 같아지는 것이다.

사이킷런에서 k-최근접 이웃 회귀 알고리즘을 구현한 클래스 KNeighborsRegressor이고, 이 객체를 생성하고 fit 메서드로 회귀모델을 훈련한다.

from sklearn.metrics import mean_absolute_error
test_prediction = knr.predict(test_input)
mae = mean_absolute_error(test_target, test_prediction)
print(mae)

19.157142857142862

mean_absolute_error()를 사용하여 타깃과 예측의 절댓값 오차를 평균하여 반환한다.

이 함수를 사용하면 타깃과 예측한 값 사이의 차이가 얼마나 나는지,

즉, 예측이 얼마나 빗나갔는지 확인이 가능하다.

그리고 그 결과 19g정도가 타깃과 다르다는 것을 알 수 있다.

지금까지는 훈련세트로 모델을 훈련하고 테스트세트를 이용하여 모델을 테스트했다.

그러면 훈련세트로 모델을 평가하면 어떻게 될까?

print(knr.score(train_input, train_target))

0.9698823289099254

앞에서 했던 테스트를 평가한 결과 0.992809406101064이 나왔고 훈련을 평가한 결과 0.9698823289099254가 나왔다.

훈련세트를 가지고 훈련을 했으니 훈련세트에서 좀더 좋은 결과가 나와야 하는데 그러지 않는 것은 이것이 과소적합이 일어났기 때문이다.

과대적합과 과소적합

과대적합

훈련세트에서 점수가 굉장히 좋았는데 테스트 세트에서 점수가 굉장히 나쁜경우

이 경우는 훈련세트에만 잘 맞는 모델이라 테스트 세트와 나중에 실전에 투입하여 새로운 샘플에 대한 예측을 만들 때 잘 동작하지 않을 것이다.

과소적합

훈련세트보다 테스트세트의 점수가 높거나 두 점수가 모두 낮은 경우

모델이 너무 단순하여 훈련세트에 적절히 훈련되지 않은 경우, 즉 훈련세트와 테스트세트의 크기가 매우 작아 모델에 필요한 데이터가 적은 경우 발생한다.

따라서 위의 과소적합을 해결하려면 우리는 모델을 좀더 복잡하게 만들어야한다.

즉, 훈련세트에 더 잘맞게 만들면 테스트점수는 조금 낮아질 것이다. 더 복잡하게 만드는 방법은 이웃의 개수를 줄이는 것이다.

이유는 k-최근접이웃알고리즘은 이웃의 개수가 많아질 수록 평균적인 값으로 근접해진다. 따라서 어떤 값이 나오던 평균과 비슷한 값으로 가기 때문에 실제 타깃과 모델이 예측하는 값이 많이 다를 것이다.

따라서 이웃의 default 개수인 5에서 3으로 줄여 훈련세트에 있는 국지적인 패턴에 민감해지도록 한다.

knr.n_neighbors = 3

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

0.9804899950518966
0.9746459963987609

예상대로 테스트 세트의 점수는 훈련세트의 점수보다 낮아졌으므로 과소적합 문제를 해결 했다.

또한 두 점수차이가 크지 않으므로 과대적합도 아니다.

'STUDY' 카테고리의 다른 글

[AI] 특성공학과 규제  (0) 2022.11.06
[AI] 선형회귀  (0) 2022.11.06
[AI] 데이터 전처리  (0) 2022.11.06
[AI] 훈련 세트와 테스트 세트  (0) 2022.10.19
Discord 봇  (0) 2020.04.23