PYTHON/데이터분석

3-1 KNN 회귀

sshhhh 2023. 9. 15.

도미와 빙어를 구분하는 머신러닝 모델을 성공적으로 개발 한 후

 

새로운 문제 등장.......농어를 무게 단위로 판매할 것이다. 

 

<농어 무게를 예측해야한다>

농의의 길이,높이,두께를 측정한 데이터로 예측할 것 -> 농어의 무게를 정확하게 측정한 샘플이 필요하다.

 

 

#KNN회귀

지도 학습 알고리즘 

- 회귀 : 분류x , 임의로 어떤 숫자 예측하여 임이의 수치를 출력 

- 분류 : 샘플을 몇 개의 클래스 중 하나로 분류

 

KNN알고리즘

1. 예측하려는 샘플에 가장 가까운 샘플 K개를 선택

2. 샘플들의 클래스를 확인하여 다수 클래스를 새로운 샘플의 클래스로 예측

 

 

 

#데이터 준비

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

 

이 데이터가 어떤 형태를 띄고 있는지 산점도로 확인

plt.scatter(perch_length, perch_weight)
plt.xlabel('length') #특성데이터
plt.ylabel('weight') #타깃
plt.show()

농어의 길이가 커짐에 따라 무게도 늘어난다.

 

 

농어 데이터를 머신러닝 모델에 사용하기 전에 

훈련세트, 테스트 세트로 나눈다.

from sklearn.model_selection import train_test_split

사이킷런의 train_test_split( ) 함수를 통해 나누었다.

train_input, test_input, train_target, test_target
= train_test_split( perch_length, perch_weight, random_state=42)

사이킷런에 사용할 훈련세트는 2차원 배열이여야한다.

reshpae( )메서드로 배열의 크기를 바꾼다.

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

#(4,)

(2,2) 로 바꾼다.

test_array = test_array.reshape(2, 2)
print(test_array.shape)

#(2, 2)

 

train_input , test_input도 2차원 배열로 바꾼다.

크기에 -1을 지정하면 나머지 원소 개수로 모두 채우라는 의미다.

1 : train_input.reshape(-1 ,1) 처럼 사용한다.

train_input = train_input.reshape(-1, 1)
test_input = test_input.reshape(-1, 1)
print(train_input.shape, test_input.shape)
#(42, 1) (14, 1)

 

이제 준비한 훈련세트를 활용하여 KNN 알고리즘을 훈련시키겠다..

 

 

#결정계수 (R²)

KNeighborsRegressor

KNN회귀 알고리즘을 구현한 클래스

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

<테스트 세트 점수 확인>

테스트 세트에 있는 샘플을 정확하게 분류한 개수의 비율 -> 정확도 

회귀에서 정확한 숫자를 맞힌다는 것은 거의 불가능하다. 임의의 수치이기 때문이다.

knr.score(test_input, test_target)

#0.992809406101064 좋은 점수이다

 

회귀의 경우에는 다른 값으로 평가하는데 이 점수를 결정계수라고 한다.

계산식

 

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)

#19.157142857142862

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

지금까지는 훈련세트를 사용해 모델을 훈련하고 테스트 세트로 모델을 평가했다.

 

그런데 훈련 세트를 사용해 평가해보면 어떨까?

즉 score( ) 메서드에 훈련 세틀르 전달하여 점수를 출력해보자. 이 값은 테스트 세트의 점수와 다를 것 이다.

 

 

#과대적합 vs 과소적합 

 

앞서 훈련한 모델을 사용해

<훈련세트의 결정계수 점수를 확인>

print(knr.score(train_input, train_target))
#0.9698823289099254

모델을 훈련세트에 훈련하면 훈련세트에 잘 맞는 모델이 만들어진다.

이 모델을 훈련세트와 테스트 세트에서 평가하면 두 값중 어느 것이 높을까?

->훈련세트에서 높게 나와야 할 것이다.

 

<모델이 훈련세트에 과대적합>

훈련세트에서 점수가 좋았는데 테스트세트에서는 점수가 굉장히 나쁘다.

-> 훈련 세트에만 잘 맞는 모델이라 테스트 세트와

    나중에 실전에 투입하여 새로운 샘플에 대한 예측을 만들때 잘 동작하지 않을 것 

 

<모델이 훈련세트에 과소적합>

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

즉 모델이 너무 단순하여 훈련세트에 적절히 훈련되지 않은 경우이다.

-> 훈련세트가 전체 데이터를 대표한다고 가정하기 때문에 훈련세트를 잘 학습하는 것이 중요하다.

 

 

<여태 진행한것>

훈련세트점수 < 테스트세트 점수 = 과소적합

 

 

해결법 :  모델을 복잡하게 만들기 -> 훈련세트에 더 잘맞게 만들기

-이웃의 개수 k를 줄이면 복잡해진다.

 

<훈련세트 점수확인>

# 이웃의 갯수를 3으로 설정합니다
knr.n_neighbors = 3
# 모델을 다시 훈련합니다
knr.fit(train_input, train_target)
print(knr.score(train_input, train_target))

#0.9804899950518966

<테스트세트 점수확인>

print(knr.score(test_input, test_target))
#0.9746459963987609

 

 

<다시 진행한 것>

훈련세트점수 > 테스트세트 점수  -> 과소적합 해결 + 두 점수 차이 크지않으므로 과대적합도 아님

 

 

 

 


결론

 

머신에게 농어의 높이, 길이 등의 수치로 무게를 예측해달라고 요청했다.

임의로 수치를 예측하는 회귀문제이다.

우리는 농어의 길이를 사용해 무게를 예측하는 KNN회귀모델을 만들었다.

 

KNN모델은 가장 먼저 가까운 k개의 이웃을 찾는다.

그 다음 이웃샘플의 타깃값을 평균

샘플의 예측값으로 사용한다.

 

 

사이킷런은 회귀점수로 결정계수의 값을 반환한다. 

1에 가까울 수록 좋다

정량적인 평가를 하고 싶다면 사이킷런에서 제공하는 다른 평가도구를 사용할 수 있다. (절댓값 오차)

 

 

모델 훈련 후 훈련세트와 테스트세트에 대해 모두 평가 점수를 구할 수 있다.

일반적으로 훈련세트 점수 > 테스트세트 점수 (조금차이)

 

과대적합 : 훈련세트점수 >>>>테스트세트 점수

과소적합 : 훈련세트점수<<테스트세트 점수 + 두 점수가 모두 낮을 경우

 

과대적합일 경우 : 모델을 덜 복잡하게 만들기 -> k값 줄임

과소적합일 경우 : 더 복잡하게 -> k값 늘림

 

'PYTHON > 데이터분석' 카테고리의 다른 글

3-3 특성 공학과 규제  (0) 2023.09.15
3-2 선형회귀  (0) 2023.09.15
2-2 데이터 전처리  (0) 2023.09.15
2-1 훈련세트와 테스트 세트  (0) 2023.09.15
1-3 마켓과 머신러닝  (0) 2023.09.15

댓글